From ebc64a089a3d394d6c985378e6a549857d094daf Mon Sep 17 00:00:00 2001 From: Victor Feyens Date: Tue, 14 May 2019 14:46:56 +0000 Subject: [PATCH] [REF] product_configurator Purposes: * Remove bridge module event_sale_product_configurator * Ease developement of product configurators AND product-based sale_order_line configurators * Fix the tests for those extensions * Note that despite the widget being extensible, the tests from the other configurators can easily crash when other configurators are installed because of query counts or limited data available in tests environments. Technical clarifications: A main product_configurator widget base in odoo/addons/sale, set on the product_product and product_template on the sale_order_line inline list, providing: * 5 hooks: * _onTemplateChange for product_product configurators based on product templates * _onProductChange for sale_order_line configurators based on product_product Those two hooks are expected to return a boolean promise to know whether the line has been configured or not, avoiding the opening of multiple wizards. * _isConfigurableProduct * _isConfigurableLine If true, a pencil button is shown next to the product/product_template, calling _onEditProductConfiguration when clicked. * _onEditProductConfiguration Called when clicking on edit pencil button. Examples : Product configurator : odoo/addons/sale_product_configurator module --> product_configurator (true one, the one in sale doesn't do anything until extended) Sale Order Line configurator : odoo/addons/event_sale/ --> event_configurator, future rental configurator --- .../src/js/event_configurator_widget.js | 143 +++++++-- .../src/js/event_configurator_widget_mixin.js | 124 -------- .../src/scss/event_configurator_widget.scss | 9 - .../static/tests/event_configurator.test.js | 8 +- .../tests/tours/event_configurator_ui.js | 21 +- addons/event_sale/views/assets.xml | 4 - addons/event_sale/views/sale_order_views.xml | 1 - .../__init__.py | 1 - .../__manifest__.py | 19 -- .../src/js/product_configurator_widget.js | 43 --- addons/sale/models/sale.py | 1 + .../src/js/product_configurator_widget.js | 210 +++++++++++++ .../static/src/scss/product_configurator.scss | 12 +- addons/sale/views/assets.xml | 1 + addons/sale/views/sale_views.xml | 19 ++ .../models/sale_order_line.py | 1 - .../src/js/product_configurator_controller.js | 14 +- .../src/js/product_configurator_renderer.js | 2 +- .../src/js/product_configurator_widget.js | 282 +++++++----------- .../src/scss/product_configurator_widget.scss | 9 - .../views/assets.xml | 3 - .../views/sale_views.xml | 24 +- 22 files changed, 481 insertions(+), 470 deletions(-) delete mode 100644 addons/event_sale/static/src/js/event_configurator_widget_mixin.js delete mode 100644 addons/event_sale/static/src/scss/event_configurator_widget.scss delete mode 100644 addons/event_sale_product_configurator/__init__.py delete mode 100644 addons/event_sale_product_configurator/__manifest__.py delete mode 100644 addons/event_sale_product_configurator/static/src/js/product_configurator_widget.js create mode 100644 addons/sale/static/src/js/product_configurator_widget.js delete mode 100644 addons/sale_product_configurator/static/src/scss/product_configurator_widget.scss diff --git a/addons/event_sale/static/src/js/event_configurator_widget.js b/addons/event_sale/static/src/js/event_configurator_widget.js index 5324a1fc16b..469bf489f6c 100644 --- a/addons/event_sale/static/src/js/event_configurator_widget.js +++ b/addons/event_sale/static/src/js/event_configurator_widget.js @@ -1,59 +1,142 @@ -odoo.define('event.configurator', function (require) { - -var relationalFields = require('web.relational_fields'); -var FieldsRegistry = require('web.field_registry'); -var EventConfiguratorWidgetMixin = require('event_sale.EventConfiguratorWidgetMixin'); +odoo.define('event_sale.product_configurator', function (require) { +var ProductConfiguratorWidget = require('sale.product_configurator'); /** - * The event configurator widget is a simple FieldMany2One that adds the capability - * to configure a product_id with event information using the event configurator wizard. + * Extension of the ProductConfiguratorWidget to support event product configuration. + * It opens when an event product_product is set. * * The event information include: * - event_id * - event_ticket_id * - * !!! It should only be used on a product_id field !!! */ -var EventConfiguratorWidget = relationalFields.FieldMany2One.extend(EventConfiguratorWidgetMixin, { - events: _.extend({}, - relationalFields.FieldMany2One.prototype.events, - EventConfiguratorWidgetMixin.events - ), +ProductConfiguratorWidget.include({ + /** + * @returns {boolean} + * + * @override + * @private + */ + _isConfigurableLine: function () { + return this.recordData.event_ok || this._super.apply(this, arguments); + }, /** - * @see _addEventConfigurationEditButton for more info + * @param {integer} productId + * @param {String} dataPointID + * @returns {Promise} stopPropagation true if a suitable configurator has been found. + * * @override + * @private */ - start: function () { + _onProductChange: function (productId, dataPointId) { + var self = this; + return this._super.apply(this, arguments).then(function (stopPropagation) { + if (stopPropagation) { + return Promise.resolve(true); + } else { + return self._checkForEvent(productId, dataPointId); + } + }); + }, + + /** + * This method will check if the productId needs configuration or not: + * + * @param {integer} productId + * @param {string} dataPointID + * @returns {Promise} stopPropagation true if the product is an event ticket. + * + * @private + */ + _checkForEvent: function (productId, dataPointId) { var self = this; - return this._super.apply(this, arguments).then(function () { - self._addEventConfigurationEditButton(); + return this._rpc({ + model: 'product.product', + method: 'read', + args: [productId, ['event_ok']], + }).then(function (result) { + if (result && result[0].event_ok) { + self._openEventConfigurator({ + default_product_id: productId + }, + dataPointId + ); + return Promise.resolve(true); + } + return Promise.resolve(false); }); }, /** - * This method is overridden to check if the product_id needs configuration or not: + * Opens the event configurator in 'edit' mode. * * @override - * @param {OdooEvent} event + * @private + */ + _onEditProductConfiguration: function () { + if (this.recordData.event_ok) { + var defaultValues = { + default_product_id: this.recordData.product_id.data.id + }; + + if (this.recordData.event_id) { + defaultValues.default_event_id = this.recordData.event_id.data.id; + } + + if (this.recordData.event_ticket_id) { + defaultValues.default_event_ticket_id = this.recordData.event_ticket_id.data.id; + } + + this._openEventConfigurator(defaultValues, this.dataPointID); + } else { + this._super.apply(this, arguments); + } + }, + + /** + * Opens the event configurator to allow configuring the SO line with events information. + * + * When the window is closed, configured values are used to trigger a 'field_changed' + * event to modify the current SO line. + * + * If the window is closed without providing the required values 'event_id' and + * 'event_ticket_id', the product_id field is cleaned. + * + * @param {Object} data various "default_" values + * @param {string} dataPointId * * @private */ - _onFieldChanged: function (event) { + _openEventConfigurator: function (data, dataPointId) { var self = this; - - this._super.apply(this, arguments); - if (!event.data.changes.product_id){ - return; - } - - var productId = event.data.changes.product_id.id; - self._checkForEvent(productId, event.data.dataPointID); + this.do_action('event_sale.event_configurator_action', { + additional_context: data, + on_close: function (result) { + if (result && result !== 'special') { + self.trigger_up('field_changed', { + dataPointID: dataPointId, + changes: result.eventConfiguration, + // VFE NOTE : Do we unselect the row after event config? + // event_sale tour is made to work without unselectRow + /*onSuccess: function (){ + self.getParent().unselectRow(); + }*/ + }); + } else { + if (!self.recordData.event_id || !self.recordData.event_ticket_id) { + self.trigger_up('field_changed', { + dataPointID: dataPointId, + changes: {product_id: false}, + }); + } + } + } + }); } }); -FieldsRegistry.add('event_configurator', EventConfiguratorWidget); -return EventConfiguratorWidget; +return ProductConfiguratorWidget; }); diff --git a/addons/event_sale/static/src/js/event_configurator_widget_mixin.js b/addons/event_sale/static/src/js/event_configurator_widget_mixin.js deleted file mode 100644 index 8e1300fb451..00000000000 --- a/addons/event_sale/static/src/js/event_configurator_widget_mixin.js +++ /dev/null @@ -1,124 +0,0 @@ -odoo.define('event_sale.EventConfiguratorWidgetMixin', function (require) { -'use strict'; - -var core = require('web.core'); -var _t = core._t; - -/** - * This mixin intends to gather methods that will be used by the event configurator. - * They're extracted here to be used by other widgets if necessary (namely the product_configurator_widget) - */ -var EventConfiguratorWidgetMixin = { - events: { - 'click .o_event_sale_js_event_configurator_edit': '_onEditEventConfiguration' - }, - /** - * This method will check if the current product set on the SO line is a configurable event. - * -> If so, we add a 'Edit Configuration' button next to the dropdown. - * - */ - _addEventConfigurationEditButton: function () { - var $inputDropdown = this.$('.o_input_dropdown'); - - if (this.recordData.event_ok && - $inputDropdown.length !== 0 && - this.$('.o_event_sale_js_event_configurator_edit').length === 0) { - var $editConfigurationButton = $('