diff --git a/addons/stock/models/stock_picking.py b/addons/stock/models/stock_picking.py
index 82ac943c093..ae5a58934c0 100644
--- a/addons/stock/models/stock_picking.py
+++ b/addons/stock/models/stock_picking.py
@@ -519,13 +519,12 @@ class Picking(models.Model):
picking_no_alert.json_popover = False
for picking in (self - picking_no_alert):
picking.json_popover = json.dumps({
- 'popoverTemplate': 'stock.PopoverStockRescheduling',
'delay_alert_date': format_datetime(self.env, picking.delay_alert_date, dt_format=False),
'late_elements': [{
- 'id': late_move.id,
- 'name': late_move.display_name,
- 'model': late_move._name,
- } for late_move in picking.move_ids.filtered(lambda m: m.delay_alert_date).move_orig_ids._delay_alert_get_documents()
+ 'id': late_move.id,
+ 'name': late_move.display_name,
+ 'model': late_move._name,
+ } for late_move in picking.move_ids.filtered(lambda m: m.delay_alert_date).move_orig_ids._delay_alert_get_documents()
]
})
diff --git a/addons/stock/static/src/js/counted_quantity_widget.js b/addons/stock/static/src/js/counted_quantity_widget.js
deleted file mode 100644
index 3a2175b1f4f..00000000000
--- a/addons/stock/static/src/js/counted_quantity_widget.js
+++ /dev/null
@@ -1,36 +0,0 @@
-/** @odoo-module alias=stock.counted_quantity_widget **/
-
-import BasicFields from 'web.basic_fields';
-import fieldRegistry from 'web.field_registry';
-
-const CountedQuantityWidgetField = BasicFields.FieldFloat.extend({
- supportedFieldTypes: ['float'],
-
- _renderReadonly: function () {
- if (this.recordData.inventory_quantity_set) {
- this.el.textContent = this._formatValue(this.recordData.inventory_quantity);
- } else {
- this.el.textContent = "";
- }
- },
-
- _onChange: function () {
- if (!this.recordData.inventory_quantity_set) {
- this.recordData.inventory_quantity_set = true;
- }
- this._super.apply(this);
- },
-
- _isSameValue: function(value) {
- // We want to trigger the update of the view when inserting 0
- if (value == 0) {
- return false;
- }
- return this._super(...arguments);
- }
-
-});
-
-fieldRegistry.add('counted_quantity_widget', CountedQuantityWidgetField);
-
-export default CountedQuantityWidgetField;
diff --git a/addons/stock/static/src/js/forecast_widget.js b/addons/stock/static/src/js/forecast_widget.js
deleted file mode 100644
index 1f7bb3fb275..00000000000
--- a/addons/stock/static/src/js/forecast_widget.js
+++ /dev/null
@@ -1,90 +0,0 @@
-odoo.define('stock.forecast_widget', function (require) {
-'use strict';
-
-const AbstractField = require('web.AbstractField');
-const fieldRegistry = require('web.field_registry');
-const field_utils = require('web.field_utils');
-const utils = require('web.utils');
-const core = require('web.core');
-const QWeb = core.qweb;
-
-const ForecastWidgetField = AbstractField.extend({
- supportedFieldTypes: ['float'],
-
- _render: function () {
- var data = Object.assign({}, this.record.data, {
- forecast_availability_str: field_utils.format.float(
- this.record.data.forecast_availability,
- this.record.fields.forecast_availability,
- this.nodeOptions
- ),
- reserved_availability_str: field_utils.format.float(
- this.record.data.reserved_availability,
- this.record.fields.reserved_availability,
- this.nodeOptions
- ),
- forecast_expected_date_str: field_utils.format.date(
- this.record.data.forecast_expected_date,
- this.record.fields.forecast_expected_date
- ),
- });
- if (data.forecast_expected_date && data.date_deadline) {
- data.forecast_is_late = data.forecast_expected_date > data.date_deadline;
- }
- data.will_be_fulfilled = utils.round_decimals(data.forecast_availability, this.record.fields.forecast_availability.digits[1]) >= utils.round_decimals(data.product_qty, this.record.fields.forecast_availability.digits[1]);
-
- this.$el.html(QWeb.render('stock.forecastWidget', data));
- this.$('.o_forecast_report_button').on('click', this._onOpenReport.bind(this));
- },
-
- isSet: function () {
- return true;
- },
-
- //--------------------------------------------------------------------------
- // Handlers
- //--------------------------------------------------------------------------
-
- /**
- * Opens the Forecast Report for the `stock.move` product.
- *
- * @param {MouseEvent} ev
- */
- _onOpenReport: function (ev) {
- ev.preventDefault();
- ev.stopPropagation();
- if (!this.recordData.id) {
- return;
- }
- this._rpc({
- model: 'stock.move',
- method: 'action_product_forecast_report',
- args: [this.recordData.id],
- }).then(action => {
- action.context = Object.assign(action.context || {}, {
- active_model: 'product.product',
- active_id: this.recordData.product_id.res_id,
- });
- this.do_action(action);
- });
- },
-});
-
-const JsonWidget = AbstractField.extend({
- supportedFieldTypes: ['char'],
-
- _render: function () {
- var value = JSON.parse(this.value);
- if (!value || !value.template) {
- this.$el.html('');
- return;
- }
- $(QWeb.render(value.template, value)).appendTo(this.$el);
- },
-});
-
-fieldRegistry.add('forecast_widget', ForecastWidgetField);
-fieldRegistry.add('json_widget', JsonWidget);
-
-return ForecastWidgetField;
-});
diff --git a/addons/stock/static/src/widgets/counted_quantity_widget.js b/addons/stock/static/src/widgets/counted_quantity_widget.js
new file mode 100644
index 00000000000..2bd47ecaedd
--- /dev/null
+++ b/addons/stock/static/src/widgets/counted_quantity_widget.js
@@ -0,0 +1,44 @@
+/** @odoo-module **/
+
+import { FloatField } from "@web/views/fields/float/float_field";
+import { registry } from "@web/core/registry";
+
+const { useEffect, useRef } = owl;
+
+export class CountedQuantityWidgetField extends FloatField {
+ setup() {
+ // Need to adapt useInputField to overide onInput and onChange
+ super.setup();
+
+ const inputRef = useRef("numpadDecimal");
+
+ useEffect(
+ (inputEl) => {
+ if (inputEl) {
+ inputEl.addEventListener("input", this.onInput.bind(this));
+ return () => {
+ inputEl.removeEventListener("input", this.onInput.bind(this));
+ };
+ }
+ },
+ () => [inputRef.el]
+ );
+ }
+
+ onInput(ev) {
+ this.props.setDirty(true);
+ return this.props.record.update({ inventory_quantity_set: true });
+ }
+
+ get formattedValue() {
+ if (
+ this.props.readonly &&
+ !this.props.value & !this.props.record.data.inventory_quantity_set
+ ) {
+ return "";
+ }
+ return super.formattedValue;
+ }
+}
+
+registry.category("fields").add("counted_quantity_widget", CountedQuantityWidgetField);
diff --git a/addons/stock/static/src/widgets/forecast_widget.js b/addons/stock/static/src/widgets/forecast_widget.js
new file mode 100644
index 00000000000..8477adb5612
--- /dev/null
+++ b/addons/stock/static/src/widgets/forecast_widget.js
@@ -0,0 +1,52 @@
+/** @odoo-module */
+
+import { FloatField } from "@web/views/fields/float/float_field";
+import { formatDate } from "@web/core/l10n/dates";
+import { formatFloat } from "@web/views/fields/formatters";
+import { registry } from "@web/core/registry";
+import { useService } from "@web/core/utils/hooks";
+
+export class ForecastWidgetField extends FloatField {
+ setup() {
+ const { data, fields } = this.props.record;
+ this.actionService = useService("action");
+ this.orm = useService("orm");
+ this.resId = data.id;
+
+ this.reservedAvailability = formatFloat(data.reserved_availability, {
+ ...fields.reserved_availability,
+ ...this.nodeOptions,
+ });
+ this.forecastExpectedDate = formatDate(
+ data.forecast_expected_date,
+ fields.forecast_expected_date
+ );
+ if (data.forecast_expected_date && data.date_deadline) {
+ this.forecastIsLate = data.forecast_expected_date > data.date_deadline;
+ }
+ this.willBeFulfilled = data.forecast_availability >= data.product_qty;
+ this.state = data.state;
+ }
+
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
+
+ /**
+ * Opens the Forecast Report for the `stock.move` product.
+ */
+ async _openReport(ev) {
+ ev.preventDefault();
+ ev.stopPropagation();
+ if (!this.resId) {
+ return;
+ }
+ const action = await this.orm.call("stock.move", "action_product_forecast_report", [
+ this.resId,
+ ]);
+ this.actionService.doAction(action);
+ }
+}
+ForecastWidgetField.template = "stock.ForecastWidget";
+
+registry.category("fields").add("forecast_widget", ForecastWidgetField);
diff --git a/addons/stock/static/src/widgets/forecast_widget.xml b/addons/stock/static/src/widgets/forecast_widget.xml
new file mode 100644
index 00000000000..5b6abdb9f78
--- /dev/null
+++ b/addons/stock/static/src/widgets/forecast_widget.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+ Available
+
+
+ Exp
+
+ Not Available
+
+
+
+
diff --git a/addons/stock/static/src/widgets/popover_widget.js b/addons/stock/static/src/widgets/popover_widget.js
new file mode 100644
index 00000000000..be8f9b910fa
--- /dev/null
+++ b/addons/stock/static/src/widgets/popover_widget.js
@@ -0,0 +1,53 @@
+/** @odoo-module */
+
+import { registry } from "@web/core/registry";
+import { _lt } from "@web/core/l10n/translation";
+import { useService } from "@web/core/utils/hooks";
+
+const { Component, onWillStart } = owl;
+
+export class JsonPpopOver extends Component {
+ setup() {
+ this.props = { ...this.props, ...JSON.parse(this.props.value) };
+ }
+}
+
+JsonPpopOver.displayName = _lt("Json Popup");
+JsonPpopOver.supportedTypes = ["char"];
+
+export class PopOverLeadDays extends JsonPpopOver {
+ setup() {
+ super.setup();
+ const user = useService("user");
+ onWillStart(async () => {
+ this.displayUOM = await user.hasGroup("uom.group_uom");
+ });
+ }
+
+ get qtyForecast() {
+ return this._formatQty("qty_forecast");
+ }
+ get qtyToOrder() {
+ return this._formatQty("qty_to_order");
+ }
+ get productMaxQty() {
+ return this._formatQty("product_max_qty");
+ }
+ get productMinQty() {
+ return this._formatQty("product_min_qty");
+ }
+
+ _formatQty(field) {
+ return this.displayUOM
+ ? `${this.props[field]} ${this.props.product_uom_name}`
+ : this.props[field];
+ }
+}
+
+PopOverLeadDays.template = "stock.leadDaysPopOver";
+
+export class ReplenishmentHistoryWidget extends JsonPpopOver {}
+ReplenishmentHistoryWidget.template = "stock.replenishmentHistory";
+
+registry.category("fields").add("lead_days_widget", PopOverLeadDays);
+registry.category("fields").add("replenishment_history_widget", ReplenishmentHistoryWidget);
diff --git a/addons/stock/static/src/widgets/popover_widget.xml b/addons/stock/static/src/widgets/popover_widget.xml
new file mode 100644
index 00000000000..f64f2568b78
--- /dev/null
+++ b/addons/stock/static/src/widgets/popover_widget.xml
@@ -0,0 +1,47 @@
+
+
+
+
Lead Times
+
+
+ The forecasted stock on the
+ is
+ below the inventory minimum of
+ : should be replenished to reach the maximum of
+ .
+
+
+
+
+ | Today |
+ |
+
+
+ |
+ |
+
+
+ | Forecasted Date |
+
+ =
+ |
+
+
+
+
+
+
+
diff --git a/addons/stock/static/src/xml/forecast_widget.xml b/addons/stock/static/src/xml/forecast_widget.xml
deleted file mode 100644
index 84b8eb140ae..00000000000
--- a/addons/stock/static/src/xml/forecast_widget.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
- Available
- Exp
- Not Available
-
-
-
diff --git a/addons/stock/static/src/xml/stock_orderpoint.xml b/addons/stock/static/src/xml/stock_orderpoint.xml
index e44c2fe72bb..b73225e7feb 100644
--- a/addons/stock/static/src/xml/stock_orderpoint.xml
+++ b/addons/stock/static/src/xml/stock_orderpoint.xml
@@ -1,41 +1,5 @@
-
-
Lead Times
-
-
- The forecasted stock on the
- is
- below the inventory minimum of
- : should be replenished to reach the maximum of
- .
-
-
-
-
- |
- Today
- |
-
-
- |
-
-
- |
- |
-
-
- |
- Forecasted Date
- |
-
- =
- |
-
-
-
-
-
-
-
diff --git a/addons/stock/wizard/stock_replenishment_info.py b/addons/stock/wizard/stock_replenishment_info.py
index 8efbed0cf52..01f48365691 100644
--- a/addons/stock/wizard/stock_replenishment_info.py
+++ b/addons/stock/wizard/stock_replenishment_info.py
@@ -42,7 +42,6 @@ class StockReplenishmentInfo(models.TransientModel):
dummy, lead_days_description = orderpoint.rule_ids._get_lead_days(
orderpoint.product_id, **orderpoints_values)
replenishment_report.json_lead_days = dumps({
- 'template': 'stock.leadDaysPopOver',
'lead_days_date': format_date(self.env, replenishment_report.orderpoint_id.lead_days_date),
'lead_days_description': lead_days_description,
'today': format_date(self.env, fields.Date.today()),
diff --git a/addons/stock/wizard/stock_replenishment_info.xml b/addons/stock/wizard/stock_replenishment_info.xml
index a7ad9d6ed41..742b18d18c9 100644
--- a/addons/stock/wizard/stock_replenishment_info.xml
+++ b/addons/stock/wizard/stock_replenishment_info.xml
@@ -9,10 +9,10 @@
-
+
-
+