summaryrefslogtreecommitdiff
path: root/addons/event_sale/static
diff options
context:
space:
mode:
authorstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
committerstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
commit3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch)
treea44932296ef4a9b71d5f010906253d8c53727726 /addons/event_sale/static
parent0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff)
initial commit 2
Diffstat (limited to 'addons/event_sale/static')
-rw-r--r--addons/event_sale/static/img/event_product-image.jpgbin0 -> 3845 bytes
-rw-r--r--addons/event_sale/static/src/js/event_configurator_controller.js38
-rw-r--r--addons/event_sale/static/src/js/event_configurator_view.js21
-rw-r--r--addons/event_sale/static/src/js/event_configurator_widget.js144
-rw-r--r--addons/event_sale/static/tests/event_configurator.test.js137
-rw-r--r--addons/event_sale/static/tests/tours/event_configurator_ui.js85
6 files changed, 425 insertions, 0 deletions
diff --git a/addons/event_sale/static/img/event_product-image.jpg b/addons/event_sale/static/img/event_product-image.jpg
new file mode 100644
index 00000000..95e0da4e
--- /dev/null
+++ b/addons/event_sale/static/img/event_product-image.jpg
Binary files differ
diff --git a/addons/event_sale/static/src/js/event_configurator_controller.js b/addons/event_sale/static/src/js/event_configurator_controller.js
new file mode 100644
index 00000000..3ae81387
--- /dev/null
+++ b/addons/event_sale/static/src/js/event_configurator_controller.js
@@ -0,0 +1,38 @@
+odoo.define('event.EventConfiguratorFormController', function (require) {
+"use strict";
+
+var FormController = require('web.FormController');
+
+/**
+ * This controller is overridden to allow configuring sale_order_lines through a popup
+ * window when a product with 'event_ok' is selected.
+ *
+ * This allows keeping an editable list view for sales order and remove the noise of
+ * those 2 fields ('event_id' + 'event_ticket_id')
+ */
+var EventConfiguratorFormController = FormController.extend({
+ /**
+ * We let the regular process take place to allow the validation of the required fields
+ * to happen.
+ *
+ * Then we can manually close the window, providing event information to the caller.
+ *
+ * @override
+ */
+ saveRecord: function () {
+ var self = this;
+ return this._super.apply(this, arguments).then(function () {
+ var state = self.renderer.state.data;
+ self.do_action({type: 'ir.actions.act_window_close', infos: {
+ eventConfiguration: {
+ event_id: {id: state.event_id.data.id},
+ event_ticket_id: {id: state.event_ticket_id.data.id}
+ }
+ }});
+ });
+ }
+});
+
+return EventConfiguratorFormController;
+
+});
diff --git a/addons/event_sale/static/src/js/event_configurator_view.js b/addons/event_sale/static/src/js/event_configurator_view.js
new file mode 100644
index 00000000..67aebba4
--- /dev/null
+++ b/addons/event_sale/static/src/js/event_configurator_view.js
@@ -0,0 +1,21 @@
+odoo.define('event.EventConfiguratorFormView', function (require) {
+"use strict";
+
+var EventConfiguratorFormController = require('event.EventConfiguratorFormController');
+var FormView = require('web.FormView');
+var viewRegistry = require('web.view_registry');
+
+/**
+ * @see EventConfiguratorFormController for more information
+ */
+var EventConfiguratorFormView = FormView.extend({
+ config: _.extend({}, FormView.prototype.config, {
+ Controller: EventConfiguratorFormController
+ }),
+});
+
+viewRegistry.add('event_configurator_form', EventConfiguratorFormView);
+
+return EventConfiguratorFormView;
+
+});
diff --git a/addons/event_sale/static/src/js/event_configurator_widget.js b/addons/event_sale/static/src/js/event_configurator_widget.js
new file mode 100644
index 00000000..eff0edd3
--- /dev/null
+++ b/addons/event_sale/static/src/js/event_configurator_widget.js
@@ -0,0 +1,144 @@
+odoo.define('event_sale.product_configurator', function (require) {
+var ProductConfiguratorWidget = require('sale.product_configurator');
+
+/**
+ * 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
+ *
+ */
+ProductConfiguratorWidget.include({
+ /**
+ * @returns {boolean}
+ *
+ * @override
+ * @private
+ */
+ _isConfigurableLine: function () {
+ return this.recordData.event_ok || this._super.apply(this, arguments);
+ },
+
+ /**
+ * @param {integer} productId
+ * @param {String} dataPointID
+ * @returns {Promise<Boolean>} stopPropagation true if a suitable configurator has been found.
+ *
+ * @override
+ * @private
+ */
+ _onProductChange: function (productId, dataPointId) {
+ var self = this;
+ return this._super.apply(this, arguments).then(function (stopPropagation) {
+ if (stopPropagation || productId === undefined) {
+ 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<Boolean>} stopPropagation true if the product is an event ticket.
+ *
+ * @private
+ */
+ _checkForEvent: function (productId, dataPointId) {
+ var self = this;
+ return this._rpc({
+ model: 'product.product',
+ method: 'read',
+ args: [productId, ['event_ok']],
+ }).then(function (result) {
+ if (Array.isArray(result) && result.length && result[0].event_ok) {
+ self._openEventConfigurator({
+ default_product_id: productId
+ },
+ dataPointId
+ );
+ return Promise.resolve(true);
+ }
+ return Promise.resolve(false);
+ });
+ },
+
+ /**
+ * Opens the event configurator in 'edit' mode.
+ *
+ * @override
+ * @private
+ */
+ _onEditLineConfiguration: 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
+ */
+ _openEventConfigurator: function (data, dataPointId) {
+ var self = this;
+ 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,
+ onSuccess: function () {
+ // Call post-init function.
+ self._onLineConfigured();
+ }
+ });
+ } else {
+ if (!self.recordData.event_id || !self.recordData.event_ticket_id) {
+ self.trigger_up('field_changed', {
+ dataPointID: dataPointId,
+ changes: {
+ product_id: false,
+ name: ''
+ },
+ });
+ }
+ }
+ }
+ });
+ }
+});
+
+
+return ProductConfiguratorWidget;
+
+});
diff --git a/addons/event_sale/static/tests/event_configurator.test.js b/addons/event_sale/static/tests/event_configurator.test.js
new file mode 100644
index 00000000..9ed0c98c
--- /dev/null
+++ b/addons/event_sale/static/tests/event_configurator.test.js
@@ -0,0 +1,137 @@
+odoo.define('event.configurator.tests', function (require) {
+ "use strict";
+
+ var FormView = require('web.FormView');
+ var testUtils = require('web.test_utils');
+ var createView = testUtils.createView;
+
+ var getArch = function (){
+ return '<form>' +
+ '<sheet>' +
+ '<field name="sale_order_line" widget="section_and_note_one2many">' +
+ '<tree editable="top"><control>' +
+ '<create string="Add a product"/>' +
+ '<create string="Add a section" context="{\'default_display_type\': \'line_section\'}"/>' +
+ '<create string="Add a note" context="{\'default_display_type\': \'line_note\'}"/>' +
+ '</control>' +
+ '<field name="product_id" widget="product_configurator" />' +
+ '</tree>' +
+ '</field>' +
+ '</sheet>' +
+ '</form>';
+ };
+
+ QUnit.module('Event Configurator', {
+ beforeEach: function () {
+ this.data = {
+ 'product.product': {
+ fields: {
+ id: {type: 'integer'},
+ event_ok: {type: 'boolean'},
+ rent_ok: {type: 'boolean'}//sale_rental purposes
+ },
+ records: [{
+ id: 1,
+ display_name: "Customizable Event",
+ event_ok: true,
+ rent_ok: false//sale_rental purposes
+ }, {
+ id: 2,
+ display_name: "Desk",
+ event_ok: false,
+ rent_ok: false//sale_rental purposes
+ }]
+ },
+ sale_order: {
+ fields: {
+ id: {type: 'integer'},
+ sale_order_line: {
+ string: 'lines',
+ type: 'one2many',
+ relation: 'sale_order_line'
+ },
+ }
+ },
+ sale_order_line: {
+ fields: {
+ product_id: {
+ string: 'product',
+ type: 'many2one',
+ relation: 'product.product'
+ },
+ event_ok: {type: 'boolean'},
+ rent_ok: {type: 'boolean'},//sale_rental purposes
+ event_id: {
+ string: 'event',
+ type: 'many2one',
+ relation: 'event'
+ },
+ event_ticket_id: {
+ string: 'event_ticket',
+ type: 'many2one',
+ relation: 'event_ticket'
+ }
+ }
+ }
+ };
+ }
+ }, function (){
+ QUnit.test('Select a regular product and verify that the event configurator is not opened', async function (assert) {
+ assert.expect(1);
+
+ var form = await createView({
+ View: FormView,
+ model: 'sale_order',
+ data: this.data,
+ arch: getArch(),
+ mockRPC: function (route, params) {
+ if (params.method === 'read' && params.args[1][0] === 'event_ok') {
+ assert.ok(true);
+ return Promise.resolve([{event_ok: false}]);
+ }
+ return this._super.apply(this, arguments);
+ },
+ intercepts: {
+ do_action: function (ev) {
+ if (ev.data.action === 'event_sale.event_configurator_action') {
+ assert.ok(false, "Should not execute the configure action");
+ }
+ },
+ }
+ });
+
+ await testUtils.dom.click(form.$("a:contains('Add a product')"));
+ await testUtils.fields.many2one.searchAndClickItem("product_id", {item: 'Desk'})
+ form.destroy();
+ });
+
+ QUnit.test('Select a configurable event and verify that the event configurator is opened', async function (assert) {
+ assert.expect(2);
+
+ var form = await createView({
+ View: FormView,
+ model: 'sale_order',
+ data: this.data,
+ arch: getArch(),
+ mockRPC: function (route, params) {
+ if (params.method === 'read' && params.args[1][0] === 'event_ok') {
+ assert.ok(true);
+ return Promise.resolve([{event_ok: true}]);
+ }
+ return this._super.apply(this, arguments);
+ },
+ intercepts: {
+ do_action: function (ev) {
+ if (ev.data.action === 'event_sale.event_configurator_action') {
+ assert.ok(true);
+ }
+ },
+ }
+ });
+
+ await testUtils.dom.click(form.$("a:contains('Add a product')"));
+ await testUtils.fields.many2one.searchAndClickItem("product_id", {item: 'Customizable Event'});
+ form.destroy();
+ });
+ });
+});
diff --git a/addons/event_sale/static/tests/tours/event_configurator_ui.js b/addons/event_sale/static/tests/tours/event_configurator_ui.js
new file mode 100644
index 00000000..a7419871
--- /dev/null
+++ b/addons/event_sale/static/tests/tours/event_configurator_ui.js
@@ -0,0 +1,85 @@
+odoo.define('event.event_configurator_tour', function (require) {
+"use strict";
+
+var tour = require('web_tour.tour');
+
+tour.register('event_configurator_tour', {
+ url: "/web",
+ test: true,
+}, [tour.stepUtils.showAppsMenuItem(), {
+ trigger: '.o_app[data-menu-xmlid="sale.sale_menu_root"]',
+ edition: 'community'
+}, {
+ trigger: '.o_app[data-menu-xmlid="sale.sale_menu_root"]',
+ edition: 'enterprise'
+}, {
+ trigger: ".o_list_button_add",
+ extra_trigger: ".o_sale_order"
+}, {
+ trigger: "a:contains('Add a product')"
+}, {
+ trigger: 'div[name="product_id"] input, div[name="product_template_id"] input',
+ run: function (actions) {
+ actions.text('Event');
+ }
+}, {
+ trigger: 'ul.ui-autocomplete a:contains("Event")',
+ run: 'click'
+}, {
+ trigger: 'div[name="event_id"] input',
+ run: 'click'
+}, {
+ trigger: 'ul.ui-autocomplete a:contains("Design")',
+ run: 'click',
+ in_modal: false
+}, {
+ trigger: 'div[name="event_ticket_id"] input',
+ run: 'click'
+}, {
+ trigger: 'ul.ui-autocomplete a:contains("VIP")',
+ run: 'click',
+ in_modal: false
+}, {
+ trigger: '.o_event_sale_js_event_configurator_ok'
+}, {
+ trigger: 'textarea[name="name"]',
+ run: function () {
+ var $textarea = $('textarea[name="name"]');
+ if ($textarea.val().includes('Design Fair Los Angeles') && $textarea.val().includes('VIP')) {
+ $textarea.addClass('tour_success');
+ }
+ }
+}, {
+ trigger: 'textarea[name="name"].tour_success',
+ run: function () {} // check
+}, {
+ trigger: 'ul.nav a:contains("Order Lines")',
+ run: 'click'
+}, {
+ trigger: 'td:contains("Event")',
+ run: 'click'
+}, {
+ trigger: '.o_edit_product_configuration'
+}, {
+ trigger: 'div[name="event_ticket_id"] input',
+ run: 'click'
+}, {
+ trigger: 'ul.ui-autocomplete a:contains("Standard")',
+ run: 'click',
+ in_modal: false
+}, {
+ trigger: '.o_event_sale_js_event_configurator_ok'
+}, {
+ trigger: 'textarea[name="name"]',
+ run: function () {
+ var $textarea = $('textarea[name="name"]');
+ if ($textarea.val().includes('Standard')) {
+ $textarea.addClass('tour_success_2');
+ }
+ }
+}, {
+ trigger: 'textarea[name="name"].tour_success_2',
+ run: function () {} // check
+}]);
+
+});