From c9ea3fcac6a2ab33a32e64e71d891bb078f7c0f6 Mon Sep 17 00:00:00 2001 From: "Tiffany Chang (tic)" Date: Wed, 7 Sep 2022 12:53:43 +0000 Subject: [PATCH] [IMP] purchase_requsition: convert custom js to OWL For original specs, see [1]. Some performance changes: the best price/date/unit price fields are now loaded by JS instead of passed via action context (allows for easier/ consistent reuse of view + now we can refresh without undoing any state changes due to buttons being pushed). [1] https://github.com/odoo/odoo/commit/f533e40f0e3f1cd34f1047b70dfdf95837d84501 closes odoo/odoo#101502 X-original-commit: 41ae508c2e6fc3c40b29b1bfc4b5dd7c4440a719 Signed-off-by: Antony Lesuisse Signed-off-by: Tiffany Chang --- addons/purchase_requisition/__manifest__.py | 10 ++- .../purchase_requisition/models/purchase.py | 6 -- .../js/purchase_order_alternatives_widget.js | 52 --------------- .../purchase_order_compare_list_renderer.js | 26 -------- ...hase_order_line_compare_list_controller.js | 66 ------------------- ...rchase_order_line_compare_list_renderer.js | 35 ---------- .../purchase_order_line_compare_list_view.js | 17 ----- ...rchase_order_line_compare_list_renderer.js | 52 +++++++++++++++ .../purchase_order_line_compare_list_view.js | 13 ++++ .../purchase_order_alternatives_widget.js | 46 +++++++++++++ .../purchase_order_alternatives_widget.scss | 3 + .../purchase_order_alternatives_widget.xml | 11 ++++ .../src/xml/purchase_order_line_compare.xml | 12 ---- .../tests/test_purchase_requisition.py | 8 ++- .../views/purchase_views.xml | 4 +- 15 files changed, 136 insertions(+), 225 deletions(-) delete mode 100644 addons/purchase_requisition/static/src/js/purchase_order_alternatives_widget.js delete mode 100644 addons/purchase_requisition/static/src/js/purchase_order_compare_list_renderer.js delete mode 100644 addons/purchase_requisition/static/src/js/purchase_order_line_compare_list_controller.js delete mode 100644 addons/purchase_requisition/static/src/js/purchase_order_line_compare_list_renderer.js delete mode 100644 addons/purchase_requisition/static/src/js/purchase_order_line_compare_list_view.js create mode 100644 addons/purchase_requisition/static/src/views/list/purchase_order_line_compare_list_renderer.js create mode 100644 addons/purchase_requisition/static/src/views/list/purchase_order_line_compare_list_view.js create mode 100644 addons/purchase_requisition/static/src/widgets/purchase_order_alternatives_widget.js create mode 100644 addons/purchase_requisition/static/src/widgets/purchase_order_alternatives_widget.scss create mode 100644 addons/purchase_requisition/static/src/widgets/purchase_order_alternatives_widget.xml delete mode 100644 addons/purchase_requisition/static/src/xml/purchase_order_line_compare.xml diff --git a/addons/purchase_requisition/__manifest__.py b/addons/purchase_requisition/__manifest__.py index 66802a19092..ce11ee6a697 100644 --- a/addons/purchase_requisition/__manifest__.py +++ b/addons/purchase_requisition/__manifest__.py @@ -27,12 +27,10 @@ are agreements you have with vendors to benefit from a predetermined pricing. ], 'assets': { 'web.assets_backend': [ - 'purchase_requisition/static/src/js/purchase_order_alternatives_widget.js', - 'purchase_requisition/static/src/js/purchase_order_compare_list_renderer.js', - 'purchase_requisition/static/src/js/purchase_order_line_compare_list_controller.js', - 'purchase_requisition/static/src/js/purchase_order_line_compare_list_renderer.js', - 'purchase_requisition/static/src/js/purchase_order_line_compare_list_view.js', - 'purchase_requisition/static/src/xml/purchase_order_line_compare.xml', + 'purchase_requisition/static/src/*/**.js', + 'purchase_requisition/static/src/views/*/**.js', + 'purchase_requisition/static/src/*/**.scss', + 'purchase_requisition/static/src/*/**.xml', ], }, 'license': 'LGPL-3', diff --git a/addons/purchase_requisition/models/purchase.py b/addons/purchase_requisition/models/purchase.py index 5f56bb9974b..1dce4aa4dc1 100644 --- a/addons/purchase_requisition/models/purchase.py +++ b/addons/purchase_requisition/models/purchase.py @@ -195,15 +195,9 @@ class PurchaseOrder(models.Model): } def action_compare_alternative_lines(self): - best_price_ids, best_date_ids, best_price_unit_ids = self.get_tender_best_lines() ctx = dict( self.env.context, search_default_groupby_product=True, - params={ - 'best_price_ids': best_price_ids, - 'best_date_ids': best_date_ids, - 'best_price_unit_ids': best_price_unit_ids, - }, ) view_id = self.env.ref('purchase_requisition.purchase_order_line_compare_tree').id return { diff --git a/addons/purchase_requisition/static/src/js/purchase_order_alternatives_widget.js b/addons/purchase_requisition/static/src/js/purchase_order_alternatives_widget.js deleted file mode 100644 index 33aceb34d1a..00000000000 --- a/addons/purchase_requisition/static/src/js/purchase_order_alternatives_widget.js +++ /dev/null @@ -1,52 +0,0 @@ -/** @odoo-module **/ - -import field_registry from 'web.field_registry'; -import { FieldMany2Many } from 'web.relational_fields'; -import PurchaseOrderCompareListRenderer from '@purchase_requisition/js/purchase_order_compare_list_renderer'; - -const FieldMany2ManySameWindow = FieldMany2Many.extend({ - - /** - * @override - */ - init: function (parent, name, record, options) { - this._super(...arguments); - this.isMany2Many = true; - }, - - /** - * Override to ensure we can't unlink a PO from itself (i.e. confusing behavior) - * @override - */ - _getRenderer: function () { - if (this.view.arch.tag === 'tree') { - return PurchaseOrderCompareListRenderer; - } - return this._super(...arguments); - }, - - /** - * Override to open record in same window w/breadcrumb extended - * @override - */ - _onOpenRecord: function (ev) { - ev.stopPropagation(); - const targetId = ev.target.state.data.find(obj => { - return obj.id === ev.data.id; - }).res_id; - // don't re-open current record - if (targetId !== this.record.res_id) { - this._rpc({ - model: this.model, - method: 'get_formview_action', - args: [[targetId]], - context: this.record.getContext(this.recordParams), - domain: this.record.getDomain(this.recordParams), - }).then(action => { - this.trigger_up('do_action', {action: action}); - }); - } - } -}); - -field_registry.add('many2many_same_window', FieldMany2ManySameWindow); diff --git a/addons/purchase_requisition/static/src/js/purchase_order_compare_list_renderer.js b/addons/purchase_requisition/static/src/js/purchase_order_compare_list_renderer.js deleted file mode 100644 index cb345c9b48e..00000000000 --- a/addons/purchase_requisition/static/src/js/purchase_order_compare_list_renderer.js +++ /dev/null @@ -1,26 +0,0 @@ -/** @odoo-module **/ - -import ListRenderer from 'web.ListRenderer'; - - -const PurchaseOrderCompareListRenderer = ListRenderer.extend({ - init: function (parent, state, params) { - this._super(...arguments); - this.active_id = parent.res_id; - }, - - /** - * @override - * @private - * @returns {Promise} - */ - _renderRow: function (record) { - const $tr = this._super(...arguments); - if (record.res_id === this.active_id && $tr.find('.o_list_record_remove').length) { - $tr.find(".o_list_record_remove").remove(); - } - return $tr; - } -}); - -export default PurchaseOrderCompareListRenderer; diff --git a/addons/purchase_requisition/static/src/js/purchase_order_line_compare_list_controller.js b/addons/purchase_requisition/static/src/js/purchase_order_line_compare_list_controller.js deleted file mode 100644 index c197299c271..00000000000 --- a/addons/purchase_requisition/static/src/js/purchase_order_line_compare_list_controller.js +++ /dev/null @@ -1,66 +0,0 @@ -/** @odoo-module **/ - -import ListController from 'web.ListController'; - -const PurchaseOrderLineCompareListController = ListController.extend({ - - // ------------------------------------------------------------------------- - // Public - // ------------------------------------------------------------------------- - - init: function (parent, model, renderer, params) { - this.context = renderer.state.getContext(); - this.best_date_ids = this.context.params.best_date_ids; - this.best_price_ids = this.context.params.best_price_ids; - this.best_price_unit_ids = this.context.params.best_price_unit_ids; - return this._super(...arguments); - }, - - // ------------------------------------------------------------------------- - // Handlers - // ------------------------------------------------------------------------- - /** - * @override - */ - _onButtonClicked: function (ev) { - if (ev.data.attrs.class && ev.data.attrs.class.split(' ').includes('o_clear_qty_buttons')) { - ev.stopPropagation(); - var self = this; - return this._callButtonAction(ev.data.attrs, ev.data.record).then(() => { - const context = this.model.localData[0] && this.model.localData[0].getContext() || {}; - return self._rpc({ - model: "purchase.order", - method: 'get_tender_best_lines', - args: [self.context.active_id], - context: context, - }).then((best_lines) => { - self.renderer.best_date_ids = best_lines[0] || []; - self.renderer.best_price_ids = best_lines[1] || []; - self.renderer.best_price_unit_ids = best_lines[2] || []; - self.reload(); - }); - }); - } else { - this._super.apply(this, arguments); - } - }, - - _onHeaderButtonClicked: async function (node) { - await this._super(...arguments); - if (node.attrs.name && node.attrs.name === 'action_clear_quantities') { - const context = this.model.localData[0] && this.model.localData[0].getContext() || {}; - const best_lines = await this._rpc({ - model: 'purchase.order', - method: 'get_tender_best_lines', - args: this.context.active_ids, - context, - }); - this.renderer.best_date_ids = best_lines[0]; - this.renderer.best_price_ids = best_lines[1]; - this.renderer.best_price_unit_ids = best_lines[2]; - this.reload(); - } - }, -}); - -export default PurchaseOrderLineCompareListController; diff --git a/addons/purchase_requisition/static/src/js/purchase_order_line_compare_list_renderer.js b/addons/purchase_requisition/static/src/js/purchase_order_line_compare_list_renderer.js deleted file mode 100644 index 9bf90ea4dc3..00000000000 --- a/addons/purchase_requisition/static/src/js/purchase_order_line_compare_list_renderer.js +++ /dev/null @@ -1,35 +0,0 @@ -/** @odoo-module **/ - -import ListRenderer from 'web.ListRenderer'; - - -const PurchaseOrderLineCompareListRenderer = ListRenderer.extend({ - - init: function (parent, state, params) { - this._super(...arguments); - this.best_date_ids = this.state.context.params.best_date_ids; - this.best_price_ids = this.state.context.params.best_price_ids; - this.best_price_unit_ids = this.state.context.params.best_price_unit_ids; - }, - - /** - * @override - * @private - * @returns {Promise} - */ - _renderRow: function (record) { - const $tr = this._super(...arguments); - if (this.best_date_ids.includes(record.res_id)) { - $tr.find('[name="date_planned"]').toggleClass('text-success'); - } - if (this.best_price_ids.includes(record.res_id)) { - $tr.find('[name="price_subtotal"]').toggleClass('text-success'); - } - if (this.best_price_unit_ids.includes(record.res_id)) { - $tr.find('[name="price_unit"]').toggleClass('text-success'); - } - return $tr; - } -}); - -export default PurchaseOrderLineCompareListRenderer; diff --git a/addons/purchase_requisition/static/src/js/purchase_order_line_compare_list_view.js b/addons/purchase_requisition/static/src/js/purchase_order_line_compare_list_view.js deleted file mode 100644 index 96782055cde..00000000000 --- a/addons/purchase_requisition/static/src/js/purchase_order_line_compare_list_view.js +++ /dev/null @@ -1,17 +0,0 @@ -/** @odoo-module **/ - -import ListView from 'web.ListView'; -import PurchaseOrderLineCompareListController from '@purchase_requisition/js/purchase_order_line_compare_list_controller'; -import PurchaseOrderLineCompareListRenderer from '@purchase_requisition/js/purchase_order_line_compare_list_renderer'; -import viewRegistry from 'web.view_registry'; - -const PurchaseOrderLineCompareListView = ListView.extend({ - config: Object.assign({}, ListView.prototype.config, { - Controller: PurchaseOrderLineCompareListController, - Renderer: PurchaseOrderLineCompareListRenderer, - }), -}); - -viewRegistry.add('purchase_order_line_compare', PurchaseOrderLineCompareListView); - -export default PurchaseOrderLineCompareListView; diff --git a/addons/purchase_requisition/static/src/views/list/purchase_order_line_compare_list_renderer.js b/addons/purchase_requisition/static/src/views/list/purchase_order_line_compare_list_renderer.js new file mode 100644 index 00000000000..e5b26831ca6 --- /dev/null +++ b/addons/purchase_requisition/static/src/views/list/purchase_order_line_compare_list_renderer.js @@ -0,0 +1,52 @@ +/** @odoo-module */ + +import { ListRenderer } from "@web/views/list/list_renderer"; + +const { onWillStart, useState, useSubEnv } = owl; + +export class PurchaseOrderLineCompareListRenderer extends ListRenderer { + setup() { + super.setup(); + this.bestFields = useState({ + best_price_ids: [], + best_date_ids: [], + best_price_unit_ids: [], + }); + onWillStart(async () => { + await this.updateBestFields(); + }); + const defaultOnClickViewButton = this.env.onClickViewButton; + useSubEnv({ + onClickViewButton: async (params) => { + await defaultOnClickViewButton(params); + await this.updateBestFields(); + } + }); + } + + async updateBestFields() { + [this.bestFields.best_price_ids, + this.bestFields.best_date_ids, + this.bestFields.best_price_unit_ids] = await this.props.list.model.orm.call( + "purchase.order", + "get_tender_best_lines", + [this.props.list.context.active_id], + { context: this.props.list.context } + ); + } + + getCellClass(column, record) { + let classNames = super.getCellClass(...arguments); + const customClassNames = []; + if (column.name === "price_subtotal" && this.bestFields.best_price_ids.includes(record.resId)) { + customClassNames.push("text-success"); + } + if (column.name === "date_planned" && this.bestFields.best_date_ids.includes(record.resId)) { + customClassNames.push("text-success"); + } + if (column.name === "price_unit" && this.bestFields.best_price_unit_ids.includes(record.resId)) { + customClassNames.push("text-success"); + } + return classNames.concat(" ", customClassNames.join(" ")); + } +} diff --git a/addons/purchase_requisition/static/src/views/list/purchase_order_line_compare_list_view.js b/addons/purchase_requisition/static/src/views/list/purchase_order_line_compare_list_view.js new file mode 100644 index 00000000000..72a8d9ceece --- /dev/null +++ b/addons/purchase_requisition/static/src/views/list/purchase_order_line_compare_list_view.js @@ -0,0 +1,13 @@ +/** @odoo-module **/ + +import { listView } from '@web/views/list/list_view'; +import { registry } from "@web/core/registry"; +import { PurchaseOrderLineCompareListRenderer } from "./purchase_order_line_compare_list_renderer"; + + +export const PurchaseOrderLineCompareListView = { + ...listView, + Renderer: PurchaseOrderLineCompareListRenderer, +}; + +registry.category("views").add("purchase_order_line_compare", PurchaseOrderLineCompareListView); diff --git a/addons/purchase_requisition/static/src/widgets/purchase_order_alternatives_widget.js b/addons/purchase_requisition/static/src/widgets/purchase_order_alternatives_widget.js new file mode 100644 index 00000000000..4ada4a25f4a --- /dev/null +++ b/addons/purchase_requisition/static/src/widgets/purchase_order_alternatives_widget.js @@ -0,0 +1,46 @@ +/** @odoo-module */ + +import { registry } from "@web/core/registry"; +import { useService } from "@web/core/utils/hooks"; +import { X2ManyField } from "@web/views/fields/x2many/x2many_field"; +import { ListRenderer } from "@web/views/list/list_renderer"; + + +export class FieldMany2ManyAltPOsRenderer extends ListRenderer { + isCurrentRecord(record) { + return record.data.id === this.env.model.root.data.id; + } +} + +FieldMany2ManyAltPOsRenderer.recordRowTemplate = "purchase_requisition.AltPOsListRenderer.RecordRow"; + +export class FieldMany2ManyAltPOs extends X2ManyField { + setup() { + this.orm = useService("orm"); + this.action = useService("action"); + // TODO: this is a terrible hack, make this a proper extension of many2many if/when possible + this.props.record.activeFields[this.props.name].widget = "many2many"; + super.setup(); + } + + /** + * Override to: avoid reopening currently open record + * open record in same window w/breadcrumb extended + * @override + */ + async openRecord(record) { + if (record.data.id !== this.props.record.data.id) { + const action = await this.orm.call(record.resModel, "get_formview_action", [[record.data.id]], { + context: this.props.context, + }); + await this.action.doAction(action); + } + } +} + +FieldMany2ManyAltPOs.components = { + ...X2ManyField.components, + ListRenderer: FieldMany2ManyAltPOsRenderer, +}; + +registry.category("fields").add("many2many_alt_pos", FieldMany2ManyAltPOs); diff --git a/addons/purchase_requisition/static/src/widgets/purchase_order_alternatives_widget.scss b/addons/purchase_requisition/static/src/widgets/purchase_order_alternatives_widget.scss new file mode 100644 index 00000000000..59d1a1468eb --- /dev/null +++ b/addons/purchase_requisition/static/src/widgets/purchase_order_alternatives_widget.scss @@ -0,0 +1,3 @@ +.o_field_many2many_alt_pos { + width: 100%; +} diff --git a/addons/purchase_requisition/static/src/widgets/purchase_order_alternatives_widget.xml b/addons/purchase_requisition/static/src/widgets/purchase_order_alternatives_widget.xml new file mode 100644 index 00000000000..3d3f524f3e4 --- /dev/null +++ b/addons/purchase_requisition/static/src/widgets/purchase_order_alternatives_widget.xml @@ -0,0 +1,11 @@ + + + + + + + activeActions and !isCurrentRecord(record) + + + + diff --git a/addons/purchase_requisition/static/src/xml/purchase_order_line_compare.xml b/addons/purchase_requisition/static/src/xml/purchase_order_line_compare.xml deleted file mode 100644 index 58c2de1d7f1..00000000000 --- a/addons/purchase_requisition/static/src/xml/purchase_order_line_compare.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - diff --git a/addons/purchase_requisition/tests/test_purchase_requisition.py b/addons/purchase_requisition/tests/test_purchase_requisition.py index 8f13844fce9..03f23ecc25c 100644 --- a/addons/purchase_requisition/tests/test_purchase_requisition.py +++ b/addons/purchase_requisition/tests/test_purchase_requisition.py @@ -150,11 +150,13 @@ class TestPurchaseRequisition(TestPurchaseRequisitionCommon): alt_po_1.order_line.date_planned += timedelta(days=1) alt_po_1.order_line.price_unit = unit_price - 10 action = orig_po.action_compare_alternative_lines() - params = action['context']['params'] - best_price_pol = self.env['purchase.order.line'].browse(params['best_price_ids']) - best_date_pol = self.env['purchase.order.line'].browse(params['best_date_ids']) + best_price_ids, best_date_ids, best_price_unit_ids = orig_po.get_tender_best_lines() + best_price_pol = self.env['purchase.order.line'].browse(best_price_ids) + best_date_pol = self.env['purchase.order.line'].browse(best_date_ids) + best_unit_price_pol = self.env['purchase.order.line'].browse(best_price_unit_ids) self.assertEqual(best_price_pol.order_id.id, alt_po_1.id, "Best price PO line was not correctly calculated") self.assertEqual(best_date_pol.order_id.id, orig_po.id, "Best date PO line was not correctly calculated") + self.assertEqual(best_unit_price_pol.order_id.id, alt_po_1.id, "Best unit price PO line was not correctly calculated") # second flow: create extra alt PO, check that all 3 POs are correctly auto-linked action = orig_po.action_create_alternative() diff --git a/addons/purchase_requisition/views/purchase_views.xml b/addons/purchase_requisition/views/purchase_views.xml index a8b67a4c63b..c899268c1bc 100644 --- a/addons/purchase_requisition/views/purchase_views.xml +++ b/addons/purchase_requisition/views/purchase_views.xml @@ -28,8 +28,8 @@

- - + +