From 989c6df74d23dc3a26a54d61b548a86c2b5b4331 Mon Sep 17 00:00:00 2001 From: Arnold Moyaux Date: Tue, 23 Aug 2022 14:06:05 +0000 Subject: [PATCH] [REF] stock: counted qty, forecast, json stock widgets to owl This pr follow the framework refactoring and translate the widgets of stock module to wowl. CountedQuantityWidgetField needs to add an upper listener on input since the function onChange and onInput of `useInputField` are not overidable. Json fields had their template in the json send from the server. With wowl, the template needs to be declare before the setup. So a new wiget is create for each template and those widgets extends the a common component that put the json content in the props. co-author svs-odoo X-original-commit: 350a7a0d6f4816ee75676b80a9a5b9769bf80fe6 Part-of: odoo/odoo#101305 --- addons/stock/models/stock_picking.py | 9 +- .../static/src/js/counted_quantity_widget.js | 36 -------- addons/stock/static/src/js/forecast_widget.js | 90 ------------------- .../src/widgets/counted_quantity_widget.js | 44 +++++++++ .../static/src/widgets/forecast_widget.js | 52 +++++++++++ .../static/src/widgets/forecast_widget.xml | 22 +++++ .../static/src/widgets/popover_widget.js | 53 +++++++++++ .../static/src/widgets/popover_widget.xml | 47 ++++++++++ .../stock/static/src/xml/forecast_widget.xml | 12 --- .../stock/static/src/xml/stock_orderpoint.xml | 51 ----------- .../stock/wizard/stock_replenishment_info.py | 1 - .../stock/wizard/stock_replenishment_info.xml | 4 +- 12 files changed, 224 insertions(+), 197 deletions(-) delete mode 100644 addons/stock/static/src/js/counted_quantity_widget.js delete mode 100644 addons/stock/static/src/js/forecast_widget.js create mode 100644 addons/stock/static/src/widgets/counted_quantity_widget.js create mode 100644 addons/stock/static/src/widgets/forecast_widget.js create mode 100644 addons/stock/static/src/widgets/forecast_widget.xml create mode 100644 addons/stock/static/src/widgets/popover_widget.js create mode 100644 addons/stock/static/src/widgets/popover_widget.xml delete mode 100644 addons/stock/static/src/xml/forecast_widget.xml 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 @@
- + - +