Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MERGE][IMP] (website)_sale_(product_configurator): improve p. configurator & exclusions #28310

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
118 changes: 0 additions & 118 deletions addons/account/static/src/js/section_and_note_fields_backend.js
Expand Up @@ -6,9 +6,6 @@ odoo.define('account.section_and_note_backend', function (require) {
// [UPDATED] now also allows configuring products on sale order.

"use strict";
var pyUtils = require('web.py_utils');
var core = require('web.core');
var _t = core._t;
var FieldChar = require('web.basic_fields').FieldChar;
var FieldOne2Many = require('web.relational_fields').FieldOne2Many;
var fieldRegistry = require('web.field_registry');
Expand Down Expand Up @@ -72,121 +69,6 @@ var SectionAndNoteListRenderer = ListRenderer.extend({
return this._super.apply(this, arguments).then(function () {
self.$('> table').addClass('o_section_and_note_list_view');
});
},
/**
* Add support for product configurator
*
* @override
* @private
*/
_onAddRecord: function (ev) {
// we don't want the browser to navigate to a the # url
ev.preventDefault();

// we don't want the click to cause other effects, such as unselecting
// the row that we are creating, because it counts as a click on a tr
ev.stopPropagation();

// but we do want to unselect current row
var self = this;
this.unselectRow().then(function () {
var context = ev.currentTarget.dataset.context;

var pricelistId = self._getPricelistId();
if (context && pyUtils.py_eval(context).open_product_configurator){
self._rpc({
model: 'ir.model.data',
method: 'xmlid_to_res_id',
kwargs: {xmlid: 'sale.sale_product_configurator_view_form'},
}).then(function (res_id) {
self.do_action({
name: _t('Configure a product'),
type: 'ir.actions.act_window',
res_model: 'sale.product.configurator',
views: [[res_id, 'form']],
target: 'new',
context: {
'default_pricelist_id': pricelistId
}
}, {
on_close: function (products) {
if (products && products !== 'special'){
self.trigger_up('add_record', {
context: self._productsToRecords(products),
forceEditable: "bottom" ,
allowWarning: true,
onSuccess: function (){
self.unselectRow();
}
});
}
}
});
});
} else {
self.trigger_up('add_record', {context: context && [context]}); // TODO write a test, the deferred was not considered
}
});
},

/**
* Will try to get the pricelist_id value from the parent sale_order form
*
* @private
* @returns {integer} pricelist_id's id
*/
_getPricelistId: function () {
var saleOrderForm = this.getParent() && this.getParent().getParent();
var stateData = saleOrderForm && saleOrderForm.state && saleOrderForm.state.data;
var pricelist_id = stateData.pricelist_id && stateData.pricelist_id.data && stateData.pricelist_id.data.id;

return pricelist_id;
},

/**
* Will map the products to appropriate record objects that are
* ready for the default_get
*
* @private
* @param {Array} products The products to transform into records
*/
_productsToRecords: function (products) {
var records = [];
_.each(products, function (product){
var record = {
default_product_id: product.product_id,
default_product_uom_qty: product.quantity
};

if (product.no_variant_attribute_values) {
var default_product_no_variant_attribute_values = [];
_.each(product.no_variant_attribute_values, function (attribute_value) {
default_product_no_variant_attribute_values.push(
[4, parseInt(attribute_value.value)]
);
});
record['default_product_no_variant_attribute_value_ids']
= default_product_no_variant_attribute_values;
}

if (product.product_custom_attribute_values) {
var default_custom_attribute_values = [];
_.each(product.product_custom_attribute_values, function (attribute_value) {
default_custom_attribute_values.push(
[0, 0, {
attribute_value_id: attribute_value.attribute_value_id,
custom_value: attribute_value.custom_value
}]
);
});
record['default_product_custom_attribute_value_ids']
= default_custom_attribute_values;
}

records.push(record);
});

return records;
}
});

Expand Down
3 changes: 2 additions & 1 deletion addons/event_sale/__manifest__.py
Expand Up @@ -20,15 +20,16 @@
""",
'depends': ['event', 'sale_management'],
'data': [
'views/assets.xml',
'views/event_views.xml',
'views/event_views_template.xml',
'views/product_views.xml',
'views/sale_order_views.xml',
'data/event_sale_data.xml',
'report/event_event_templates.xml',
'security/ir.model.access.csv',
'security/event_security.xml',
'wizard/event_edit_registration.xml',
'wizard/event_configurator_views.xml',
],
'demo': ['data/event_demo.xml'],
'installable': True,
Expand Down
38 changes: 38 additions & 0 deletions 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;

});
92 changes: 92 additions & 0 deletions addons/event_sale/static/src/js/event_configurator_test_ui.js
@@ -0,0 +1,92 @@
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.STEPS.SHOW_APPS_MENU_ITEM, {
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',
run: function (){
var $input = $('div[name="product_id"] input');
$input.click();
$input.val('EVENT');
// fake keydown to trigger search
var keyDownEvent = jQuery.Event("keydown");
keyDownEvent.which = 42;
$input.trigger(keyDownEvent);
},
id: 'product_selection_step'
}, {
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_event_sale_js_event_configurator_edit'
}, {
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
}]);

});
21 changes: 21 additions & 0 deletions 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;

});
59 changes: 59 additions & 0 deletions addons/event_sale/static/src/js/event_configurator_widget.js
@@ -0,0 +1,59 @@
odoo.define('event.configurator', function (require) {

var relationalFields = require('web.relational_fields');
var FieldsRegistry = require('web.field_registry');
var EventConfiguratorWidgetMixin = require('event_sale.EventConfiguratorWidgetMixin');

/**
* 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.
*
* 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
),

/**
* @see _addEventConfigurationEditButton for more info
* @override
*/
start: function () {
var self = this;
return this._super.apply(this, arguments).then(function () {
self._addEventConfigurationEditButton();
});
},

/**
* This method is overridden to check if the product_id needs configuration or not:
*
* @override
* @param {OdooEvent} event
*
* @private
*/
_onFieldChanged: function (event) {
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);
}
});

FieldsRegistry.add('event_configurator', EventConfiguratorWidget);

return EventConfiguratorWidget;

});