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 + = +
+
+ +
+

Sales History

+
+ + + + + + + + +
+
+
+
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 - - = -
-
- - -
-

Sales History

-
- - - - - - - - -
-
-
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 @@
- + - +