From 46e2d9e09c94ebe1dc69d978d33ebfbf4674458a Mon Sep 17 00:00:00 2001 From: "Ahmed Khalaf (ahkh)" Date: Fri, 26 Aug 2022 08:49:13 +0000 Subject: [PATCH] [IMP] stock, mrp: popover widget and extenstions to owl This commit converts `popover_widget`, `stock_rescheduling_popover` and `mrp_workorder_popover` to OWL closes odoo/odoo#101987 Signed-off-by: Arnold Moyaux (arm) --- addons/mrp/models/mrp_production.py | 9 +- .../static/src/js/mrp_workorder_popover.js | 48 ---------- .../src/widgets/mrp_workorder_popover.js | 41 ++++++++ .../src/widgets/mrp_workorder_popover.xml | 12 +++ addons/mrp/static/src/xml/mrp.xml | 11 --- .../sale_stock/static/src/xml/sale_stock.xml | 6 +- addons/stock/static/src/js/popover_widget.js | 85 ---------------- .../src/js/stock_rescheduling_popover.js | 39 -------- .../stock/static/src/widgets/json_widget.js | 53 ++++++++++ .../stock/static/src/widgets/json_widget.xml | 47 +++++++++ .../static/src/widgets/popover_widget.js | 94 +++++++++--------- .../static/src/widgets/popover_widget.xml | 49 ++-------- .../src/widgets/stock_rescheduling_popover.js | 42 ++++++++ .../widgets/stock_rescheduling_popover.xml | 12 +++ .../stock/static/src/xml/popover_widget.xml | 19 ---- .../static/tests/popover_widget_tests.js | 96 ++++++++++--------- addons/stock/views/stock_picking_views.xml | 2 +- 17 files changed, 321 insertions(+), 344 deletions(-) delete mode 100644 addons/mrp/static/src/js/mrp_workorder_popover.js create mode 100644 addons/mrp/static/src/widgets/mrp_workorder_popover.js create mode 100644 addons/mrp/static/src/widgets/mrp_workorder_popover.xml delete mode 100644 addons/mrp/static/src/xml/mrp.xml delete mode 100644 addons/stock/static/src/js/popover_widget.js delete mode 100644 addons/stock/static/src/js/stock_rescheduling_popover.js create mode 100644 addons/stock/static/src/widgets/json_widget.js create mode 100644 addons/stock/static/src/widgets/json_widget.xml create mode 100644 addons/stock/static/src/widgets/stock_rescheduling_popover.js create mode 100644 addons/stock/static/src/widgets/stock_rescheduling_popover.xml delete mode 100644 addons/stock/static/src/xml/popover_widget.xml diff --git a/addons/mrp/models/mrp_production.py b/addons/mrp/models/mrp_production.py index eba51807078..b7b339570ca 100644 --- a/addons/mrp/models/mrp_production.py +++ b/addons/mrp/models/mrp_production.py @@ -402,13 +402,12 @@ class MrpProduction(models.Model): production_no_alert.json_popover = False for production in (self - production_no_alert): production.json_popover = json.dumps({ - 'popoverTemplate': 'stock.PopoverStockRescheduling', 'delay_alert_date': format_datetime(self.env, production.delay_alert_date, dt_format=False), 'late_elements': [{ - 'id': late_document.id, - 'name': late_document.display_name, - 'model': late_document._name, - } for late_document in production.move_raw_ids.filtered(lambda m: m.delay_alert_date).move_orig_ids._delay_alert_get_documents() + 'id': late_document.id, + 'name': late_document.display_name, + 'model': late_document._name, + } for late_document in production.move_raw_ids.filtered(lambda m: m.delay_alert_date).move_orig_ids._delay_alert_get_documents() ] }) diff --git a/addons/mrp/static/src/js/mrp_workorder_popover.js b/addons/mrp/static/src/js/mrp_workorder_popover.js deleted file mode 100644 index 94a9819d138..00000000000 --- a/addons/mrp/static/src/js/mrp_workorder_popover.js +++ /dev/null @@ -1,48 +0,0 @@ -/** @odoo-module **/ - -import PopoverWidget from 'stock.popover_widget'; -import fieldRegistry from 'web.field_registry'; -import { _t } from 'web.core'; - - -/** - * Link to a Char field representing a JSON: - * { - * 'replan': , // Show the replan btn - * 'color': '', // Color Class of the icon (d-none to hide) - * 'infos': [ - * {'msg' : '', 'color' : ''}, - * {'msg' : '', 'color' : ''}, - * ... ] - * } - */ -var MrpWorkorderPopover = PopoverWidget.extend({ - popoverTemplate: 'mrp.workorderPopover', - title: _t('Scheduling Information'), - - _render: function () { - this._super.apply(this, arguments); - if (! this.$popover) { - return; - } - var self = this; - this.$popover.find('.action_replan_button').click(function (e) { - self._onReplanClick(e); - }); - }, - - _onReplanClick:function (e) { - var self = this; - this._rpc({ - model: 'mrp.workorder', - method: 'action_replan', - args: [[self.res_id]] - }).then(function () { - self.trigger_up('reload'); - }); - }, -}); - -fieldRegistry.add('mrp_workorder_popover', MrpWorkorderPopover); - -export default MrpWorkorderPopover; diff --git a/addons/mrp/static/src/widgets/mrp_workorder_popover.js b/addons/mrp/static/src/widgets/mrp_workorder_popover.js new file mode 100644 index 00000000000..4a86edb7bf3 --- /dev/null +++ b/addons/mrp/static/src/widgets/mrp_workorder_popover.js @@ -0,0 +1,41 @@ +/** @odoo-module */ +import { useService } from "@web/core/utils/hooks"; +import { registry } from "@web/core/registry"; +import { PopoverComponent, PopoverWidgetField } from '@stock/widgets/popover_widget'; + +/** + * Link to a Char field representing a JSON: + * { + * 'replan': , // Show the replan btn + * 'color': '', // Color Class of the icon (d-none to hide) + * 'infos': [ + * {'msg' : '', 'color' : ''}, + * {'msg' : '', 'color' : ''}, + * ... ] + * } + */ + +class WorkOrderPopover extends PopoverComponent { + setup(){ + this.orm = useService("orm"); + } + + async onReplanClick() { + await this.orm.call( + 'mrp.workorder', + 'action_replan', + [this.props.record.resId] + ); + await this.props.record.model.load(); + } +}; + +WorkOrderPopover.template = 'mrp.workorderPopover'; + +class WorkOrderPopoverField extends PopoverWidgetField {}; + +WorkOrderPopoverField.components = { + Popover: WorkOrderPopover +}; + +registry.category("fields").add("mrp_workorder_popover", WorkOrderPopoverField); \ No newline at end of file diff --git a/addons/mrp/static/src/widgets/mrp_workorder_popover.xml b/addons/mrp/static/src/widgets/mrp_workorder_popover.xml new file mode 100644 index 00000000000..ad85e50261e --- /dev/null +++ b/addons/mrp/static/src/widgets/mrp_workorder_popover.xml @@ -0,0 +1,12 @@ + + + +
+
Scheduling Information
+ +
+
+ +
+ +
diff --git a/addons/mrp/static/src/xml/mrp.xml b/addons/mrp/static/src/xml/mrp.xml deleted file mode 100644 index ee56d09f4cb..00000000000 --- a/addons/mrp/static/src/xml/mrp.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - -
- -
-
- -
- -
diff --git a/addons/sale_stock/static/src/xml/sale_stock.xml b/addons/sale_stock/static/src/xml/sale_stock.xml index 34000cc01bb..ba28b1b12f8 100644 --- a/addons/sale_stock/static/src/xml/sale_stock.xml +++ b/addons/sale_stock/static/src/xml/sale_stock.xml @@ -64,10 +64,10 @@ -
+

The delivery - - , + + , will be late.

diff --git a/addons/stock/static/src/js/popover_widget.js b/addons/stock/static/src/js/popover_widget.js deleted file mode 100644 index 1eea84a2e6c..00000000000 --- a/addons/stock/static/src/js/popover_widget.js +++ /dev/null @@ -1,85 +0,0 @@ -odoo.define('stock.popover_widget', function (require) { -'use strict'; - -var AbstractField = require('web.AbstractField'); -var core = require('web.core'); -var QWeb = core.qweb; -var Context = require('web.Context'); -var fieldRegistry = require('web.field_registry'); - -/** - * Widget Popover for JSON field (char), by default render a simple html message - * { - * 'msg': '', - * 'icon': '' (optionnal), - * 'color': '' (optionnal), - * 'title': '' (optionnal), - * 'popoverTemplate': '<TEMPLATE OF THE TEMPLATE>' (optionnal) - * } - */ -var PopoverWidgetField = AbstractField.extend({ - supportedFieldTypes: ['char'], - buttonTemplape: 'stock.popoverButton', - popoverTemplate: 'stock.popoverContent', - trigger: 'focus', - placement: 'top', - html: true, - color: 'text-primary', - icon: 'fa-info-circle', - - _render: function () { - var value = JSON.parse(this.value); - if (!value) { - this.$el.html(''); - return; - } - this.$el.css('max-width', '17px'); - this.$el.html(QWeb.render(this.buttonTemplape, _.defaults(value, {color: this.color, icon: this.icon}))); - this.$el.addClass('o_widget'); - this.$el.find('a').prop('special_click', true); - this.$popover = $(QWeb.render(value.popoverTemplate || this.popoverTemplate, value)); - this.$popover.on('click', '.action_open_forecast', this._openForecast.bind(this)); - this.$el.find('a').popover({ - content: this.$popover, - html: this.html, - placement: this.placement, - title: value.title || this.title.toString(), - trigger: this.trigger, - delay: {'show': 0, 'hide': 100}, - }); - }, - - /** - * Redirect to the product forecasted report. - * - * @private - * @param {MouseEvent} event - * @returns {Promise} action loaded - */ - async _openForecast(ev) { - ev.stopPropagation(); - const reportContext = { - active_model: 'product.product', - active_id: this.recordData.product_id.data.id, - warehouse: this.recordData.warehouse_id.data.id, - }; - const action = await this._rpc({ - model: reportContext.active_model, - method: 'action_product_forecast_report', - args: [[reportContext.active_id]], - }); - action.context = new Context(action.context, reportContext); - return this.do_action(action); - }, - - destroy: function () { - this.$el.find('a').popover('dispose'); - this._super.apply(this, arguments); - }, - -}); - -fieldRegistry.add('popover_widget', PopoverWidgetField); - -return PopoverWidgetField; -}); diff --git a/addons/stock/static/src/js/stock_rescheduling_popover.js b/addons/stock/static/src/js/stock_rescheduling_popover.js deleted file mode 100644 index c3959642f24..00000000000 --- a/addons/stock/static/src/js/stock_rescheduling_popover.js +++ /dev/null @@ -1,39 +0,0 @@ -odoo.define('stock.PopoverStockPicking', function (require) { -"use strict"; - -var core = require('web.core'); - -var PopoverWidgetField = require('stock.popover_widget'); -var registry = require('web.field_registry'); -var _lt = core._lt; - -var PopoverStockPicking = PopoverWidgetField.extend({ - title: _lt('Planning Issue'), - trigger: 'focus', - color: 'text-danger', - icon: 'fa-exclamation-triangle', - - _render: function () { - this._super(); - if (this.$popover) { - var self = this; - this.$popover.find('a').on('click', function (ev) { - ev.preventDefault(); - ev.stopPropagation(); - self.do_action({ - type: 'ir.actions.act_window', - res_model: ev.currentTarget.getAttribute('element-model'), - res_id: parseInt(ev.currentTarget.getAttribute('element-id'), 10), - views: [[false, 'form']], - target: 'current' - }); - }); - } - }, - -}); - -registry.add('stock_rescheduling_popover', PopoverStockPicking); - -return PopoverStockPicking; -}); diff --git a/addons/stock/static/src/widgets/json_widget.js b/addons/stock/static/src/widgets/json_widget.js new file mode 100644 index 00000000000..be8f9b910fa --- /dev/null +++ b/addons/stock/static/src/widgets/json_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/json_widget.xml b/addons/stock/static/src/widgets/json_widget.xml new file mode 100644 index 00000000000..f64f2568b78 --- /dev/null +++ b/addons/stock/static/src/widgets/json_widget.xml @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="utf-8"?> +<templates id="template" xml:space="preserve"> + <div t-name="stock.leadDaysPopOver" owl="1"> + <h2>Lead Times</h2> + <hr/> + <p> + The forecasted stock on the <b t-esc="props.lead_days_date"/> + is <t t-if="props.qty_to_order <= 0"><b><t t-esc="qtyForecast"/></b></t><t t-else=""> + below the inventory <b>minimum of <t t-esc="productMinQty"/> + : <t t-esc="qtyToOrder"/> should be replenished</b> to reach the maximum of + <t t-esc="productMaxQty"/>.</t> + </p> + <table t-if="props.lead_days_description" class="table table-borderless table-sm"> + <tbody> + <tr> + <td>Today</td> + <td class="text-end" t-out="props.today"/> + </tr> + <tr t-foreach="props.lead_days_description" t-key="descr" t-as="descr"> + <td t-out="descr[0]"/> + <td class="text-end" t-out="descr[1]"/> + </tr> + <tr class="table-info"> + <td>Forecasted Date</td> + <td class="text-end text-nowrap"> + = <t t-out="props.lead_days_date"/> + </td> + </tr> + </tbody> + </table> + </div> + + <div t-name="stock.replenishmentHistory" owl="1"> + <h2>Sales History</h2> + <hr/> + <table t-if="props.replenishment_history" class="table table-borderless"> + <tbody> + <t t-foreach="props.replenishment_history" t-key="line" t-as="line"> + <tr> + <td><t t-esc="line.name"/></td> + <td class="text-end text-nowrap" t-esc="line.quantity + ' ' + line.uom_name"/> + </tr> + </t> + </tbody> + </table> + </div> +</templates> diff --git a/addons/stock/static/src/widgets/popover_widget.js b/addons/stock/static/src/widgets/popover_widget.js index be8f9b910fa..22a56a9a2ec 100644 --- a/addons/stock/static/src/widgets/popover_widget.js +++ b/addons/stock/static/src/widgets/popover_widget.js @@ -1,53 +1,55 @@ /** @odoo-module */ - import { registry } from "@web/core/registry"; -import { _lt } from "@web/core/l10n/translation"; -import { useService } from "@web/core/utils/hooks"; +import { usePopover } from "@web/core/popover/popover_hook"; +const { Component } = owl; -const { Component, onWillStart } = owl; -export class JsonPpopOver extends Component { - setup() { - this.props = { ...this.props, ...JSON.parse(this.props.value) }; +/** + * Extend this to add functionality to Popover (custom methods etc.) + * need to extend PopoverWidgetField as well and set its Popover Component to new extension + */ +export class PopoverComponent extends Component {} +PopoverComponent.template = 'stock.popoverContent'; + +/** + * Widget Popover for JSON field (char), renders a popover above an icon button on click + * { + * 'msg': '<CONTENT OF THE POPOVER>' required if not 'popoverTemplate' is given, + * 'icon': '<FONT AWESOME CLASS>' default='fa-info-circle', + * 'color': '<COLOR CLASS OF ICON>' default='text-primary', + * 'position': <POSITION OF THE POPOVER> default='top', + * 'popoverTemplate': '<TEMPLATE OF THE POPOVER>' default='stock.popoverContent' + * pass a template for popover to use, other data passed in JSON field will be passed + * to popover template inside props (ex. props.someValue), must be owl template + * } + */ + +export class PopoverWidgetField extends Component { + setup(){ + this.popover = usePopover(); + this.closePopover = null; + let fieldValue = this.props.record.data[this.props.name]; + this.jsonValue = JSON.parse(fieldValue); + this.color = this.jsonValue.color || 'text-primary'; + this.icon = this.jsonValue.icon || 'fa-info-circle'; + } + + showPopup(ev){ + if (this.jsonValue.popoverTemplate){ + this.constructor.components.Popover.template = this.jsonValue.popoverTemplate; + } + this.closePopover = this.popover.add( + ev.currentTarget, + this.constructor.components.Popover, + {...this.jsonValue, record: this.props.record}, + { + position: this.jsonValue.position || 'top', + } + ); } } -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); +PopoverWidgetField.supportedTypes = ['char']; +PopoverWidgetField.template = 'stock.popoverButton'; +PopoverWidgetField.components = { Popover: PopoverComponent } +registry.category("fields").add("popover_widget", PopoverWidgetField); diff --git a/addons/stock/static/src/widgets/popover_widget.xml b/addons/stock/static/src/widgets/popover_widget.xml index f64f2568b78..f99add16a55 100644 --- a/addons/stock/static/src/widgets/popover_widget.xml +++ b/addons/stock/static/src/widgets/popover_widget.xml @@ -1,47 +1,12 @@ <?xml version="1.0" encoding="utf-8"?> <templates id="template" xml:space="preserve"> - <div t-name="stock.leadDaysPopOver" owl="1"> - <h2>Lead Times</h2> - <hr/> - <p> - The forecasted stock on the <b t-esc="props.lead_days_date"/> - is <t t-if="props.qty_to_order <= 0"><b><t t-esc="qtyForecast"/></b></t><t t-else=""> - below the inventory <b>minimum of <t t-esc="productMinQty"/> - : <t t-esc="qtyToOrder"/> should be replenished</b> to reach the maximum of - <t t-esc="productMaxQty"/>.</t> - </p> - <table t-if="props.lead_days_description" class="table table-borderless table-sm"> - <tbody> - <tr> - <td>Today</td> - <td class="text-end" t-out="props.today"/> - </tr> - <tr t-foreach="props.lead_days_description" t-key="descr" t-as="descr"> - <td t-out="descr[0]"/> - <td class="text-end" t-out="descr[1]"/> - </tr> - <tr class="table-info"> - <td>Forecasted Date</td> - <td class="text-end text-nowrap"> - = <t t-out="props.lead_days_date"/> - </td> - </tr> - </tbody> - </table> - </div> - <div t-name="stock.replenishmentHistory" owl="1"> - <h2>Sales History</h2> - <hr/> - <table t-if="props.replenishment_history" class="table table-borderless"> - <tbody> - <t t-foreach="props.replenishment_history" t-key="line" t-as="line"> - <tr> - <td><t t-esc="line.name"/></td> - <td class="text-end text-nowrap" t-esc="line.quantity + ' ' + line.uom_name"/> - </tr> - </t> - </tbody> - </table> + <t t-name="stock.popoverButton" owl="1"> + <a tabindex="0" t-on-click.stop="showPopup" t-attf-class="p-1 fa #{ icon || 'fa-info-circle'} #{ color || 'text-primary'}"/> + </t> + + <div t-name="stock.popoverContent" owl="1" class="m-3"> + <h6 t-out="props.title"/> + <t t-out="props.msg"/> </div> </templates> diff --git a/addons/stock/static/src/widgets/stock_rescheduling_popover.js b/addons/stock/static/src/widgets/stock_rescheduling_popover.js new file mode 100644 index 00000000000..e82eee5ce35 --- /dev/null +++ b/addons/stock/static/src/widgets/stock_rescheduling_popover.js @@ -0,0 +1,42 @@ +/** @odoo-module */ +import { useService } from "@web/core/utils/hooks"; +import { registry } from "@web/core/registry"; +import { PopoverComponent, PopoverWidgetField } from '@stock/widgets/popover_widget'; + +class StockRescheculingPopoverComponent extends PopoverComponent { + setup(){ + this.action = useService("action"); + } + + openElement(ev){ + this.action.doAction({ + res_model: ev.currentTarget.getAttribute('element-model'), + res_id: parseInt(ev.currentTarget.getAttribute('element-id')), + views: [[false, "form"]], + type: "ir.actions.act_window", + view_mode: "form", + }); + } +} + +StockRescheculingPopoverComponent.template ='stock.PopoverStockRescheduling'; + +class StockRescheculingPopover extends PopoverWidgetField { + setup(){ + super.setup(); + this.color = this.jsonValue.color || 'text-danger'; + this.icon = this.jsonValue.icon || 'fa-exclamation-triangle'; + } + + showPopup(ev){ + if (!this.jsonValue.late_elements){ + return; + } + super.showPopup(ev); + } +} +StockRescheculingPopover.components = { + Popover: StockRescheculingPopoverComponent +} + +registry.category("fields").add("stock_rescheduling_popover", StockRescheculingPopover); diff --git a/addons/stock/static/src/widgets/stock_rescheduling_popover.xml b/addons/stock/static/src/widgets/stock_rescheduling_popover.xml new file mode 100644 index 00000000000..b9b9376f407 --- /dev/null +++ b/addons/stock/static/src/widgets/stock_rescheduling_popover.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<templates> + + <div t-name="stock.PopoverStockRescheduling" owl="1" class="m-3"> + <h6>Planning Issue</h6> + <p>Preceding operations + <t t-foreach="props.late_elements" t-as="late_element" t-key="late_element.id"> + <a t-out="late_element.name" t-on-click="openElement" href="#" t-att-element-id="late_element.id" t-att-element-model="late_element.model"/>, + </t> + planned on <t t-out="props.delay_alert_date"/>.</p> + </div> +</templates> diff --git a/addons/stock/static/src/xml/popover_widget.xml b/addons/stock/static/src/xml/popover_widget.xml deleted file mode 100644 index d5c503565ec..00000000000 --- a/addons/stock/static/src/xml/popover_widget.xml +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<templates id="template" xml:space="preserve"> - - <t t-name="stock.popoverButton"> - <a tabindex="0" t-attf-class="p-1 fa #{ icon || 'fa-info-circle'} #{ color || 'text-primary'}"/> - </t> - - <div t-name="stock.popoverContent"> - <t t-esc="msg"/> - </div> - - <div t-name="stock.PopoverStockRescheduling"> - <p>Preceding operations - <t t-foreach="late_elements" t-as="late_element"> - <a t-esc="late_element.name" href="#" t-att-element-id="late_element.id" t-att-element-model="late_element.model"/>, - </t> - planned on <t t-esc="delay_alert_date"/>.</p> - </div> -</templates> diff --git a/addons/stock/static/tests/popover_widget_tests.js b/addons/stock/static/tests/popover_widget_tests.js index 0e2ea8b32e2..9018d181841 100644 --- a/addons/stock/static/tests/popover_widget_tests.js +++ b/addons/stock/static/tests/popover_widget_tests.js @@ -1,53 +1,59 @@ -odoo.define('stock.popover_widget_tests', function (require) { -"use strict"; +/** @odoo-module **/ -var testUtils = require('web.test_utils'); -var FormView = require('web.FormView'); -var createView = testUtils.createView; +import { getFixture, click } from "@web/../tests/helpers/utils"; -QUnit.module('widgets', {}, function () { -QUnit.module('ModelFieldSelector', { - beforeEach: function () { - this.data = { - partner: { - fields: { - json_data: {string: " ", type: "char"}, - }, - records: [ - {id:1, json_data:'{"color": "text-danger", "msg": "var that = self // why not?", "title": "JS Master"}'} - ] - } - }; - }, -}, function () { - QUnit.test("Test creation/usage popover widget form", async function (assert) { - assert.expect(6); +import { makeView, setupViewRegistries } from "@web/../tests/views/helpers"; + +let target; +let serverData + +QUnit.module('widgets', ()=> { + QUnit.module('PopoverWidget', hooks => { + hooks.beforeEach(()=>{ + target = getFixture(); + setupViewRegistries(); + serverData = { + models: { + partner: { + fields: { + json_data: {string: " ", type: "char"}, + }, + records: [ + {id:1, json_data:'{"color": "text-danger", "msg": "var that = self // why not?", "title": "JS Master"}'} + ] + } + } + }; - var form = await createView({ - View: FormView, - model: 'partner', - data: this.data, - arch:'<form string="Partners">' + - '<field name="json_data" widget="popover_widget"/>' + - '</form>', - res_id: 1 }); - var $popover = $('div.popover'); - assert.strictEqual($popover.length, 0, "Shouldn't have a popover container in DOM"); + QUnit.test('Test creation/usage form popover widget', async assert => { + assert.expect(5); + await makeView({ + type: "form", + resModel: "partner", + serverData, + arch: ` + <form> + <field name="json_data" widget="popover_widget"/> + </form>`, + resId: 1, + }); + assert.containsNone(target, 'div.popover', "Shouldn't have a popover container in DOM"); + assert.containsOnce(target, 'a.fa.fa-info-circle.text-danger', "Should have a popover icon/button in red"); + await click(target, 'a.fa.fa-info-circle.text-danger'); + assert.containsOnce(target, 'div.popover', "Should have a popover icon/button in red"); + assert.strictEqual( + target.querySelector("div.popover").innerHTML.includes("var that = self // why not?"), + true, + "The message should be in DOM" + ); + assert.strictEqual( + target.querySelector("div.popover").innerHTML.includes("JS Master"), + true, + "The title should be in DOM" + ); - var $popoverButton = form.$('a.fa.fa-info-circle.text-danger'); - assert.strictEqual($popoverButton.length, 1, "Should have a popover icon/button in red"); - assert.strictEqual($popoverButton.prop('special_click'), true, "Special click properpy should be activated"); - await testUtils.dom.triggerEvent($popoverButton, 'focusin'); - $popover = $('div.popover'); - assert.strictEqual($popover.length, 1, "Should have a popover container in DOM"); - assert.strictEqual($popover.html().includes("var that = self // why not?"), true, "The message should be in DOM"); - assert.strictEqual($popover.html().includes("JS Master"), true, "The title should be in DOM"); - - form.destroy(); + }); }); }); -}); - -}); diff --git a/addons/stock/views/stock_picking_views.xml b/addons/stock/views/stock_picking_views.xml index 9af1801a3eb..a24535bd828 100644 --- a/addons/stock/views/stock_picking_views.xml +++ b/addons/stock/views/stock_picking_views.xml @@ -94,7 +94,7 @@ decoration-success="state == 'done'" decoration-warning="state not in ('draft','cancel','done','assigned')"/> <field name="activity_exception_decoration" widget="activity_exception"/> - <field name="json_popover" nolabel="1" widget="stock_rescheduling_popover" attrs="{'invisible': [('json_popover', '=', False)]}"/> + <field name="json_popover" widget="stock_rescheduling_popover" nolabel="1" attrs="{'invisible': [('json_popover', '=', False)]}"/> </tree> </field> </record>