[MIG] web_widget_one2many_product_picker: Migration to 13.0

This commit is contained in:
Alexandre D. Díaz
2021-03-16 20:12:45 +01:00
parent eb1a53d92a
commit b453c9784e
18 changed files with 947 additions and 916 deletions

View File

@@ -14,16 +14,16 @@ Web Widget One2Many Product Picker
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fweb-lightgray.png?logo=github
:target: https://github.com/OCA/web/tree/12.0/web_widget_one2many_product_picker
:target: https://github.com/OCA/web/tree/13.0/web_widget_one2many_product_picker
:alt: OCA/web
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/web-12-0/web-12-0-web_widget_one2many_product_picker
:target: https://translation.odoo-community.org/projects/web-13-0/web-13-0-web_widget_one2many_product_picker
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
:target: https://runbot.odoo-community.org/runbot/162/12.0
:target: https://runbot.odoo-community.org/runbot/162/13.0
:alt: Try me on Runbot
|badge1| |badge2| |badge3| |badge4| |badge5|
|badge1| |badge2| |badge3| |badge4| |badge5|
Adds the 'one2many_product_picker' friendly mobile widget to create one2many lines linked with product.product records.
@@ -196,12 +196,12 @@ accept changes.
Parts of the widget:
~~~~~~~~~~~~~~~~~~~~
.. image:: https://raw.githubusercontent.com/OCA/web/12.0/web_widget_one2many_product_picker/static/img/product_picker_anat.png
.. image:: https://raw.githubusercontent.com/OCA/web/13.0/web_widget_one2many_product_picker/static/img/product_picker_anat.png
Preview:
~~~~~~~~
.. image:: https://raw.githubusercontent.com/OCA/web/12.0/web_widget_one2many_product_picker/static/img/product_picker.gif
.. image:: https://raw.githubusercontent.com/OCA/web/13.0/web_widget_one2many_product_picker/static/img/product_picker.gif
Known issues / Roadmap
======================
@@ -215,7 +215,7 @@ Bug Tracker
Bugs are tracked on `GitHub Issues <https://github.com/OCA/web/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed
`feedback <https://github.com/OCA/web/issues/new?body=module:%20web_widget_one2many_product_picker%0Aversion:%2012.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
`feedback <https://github.com/OCA/web/issues/new?body=module:%20web_widget_one2many_product_picker%0Aversion:%2013.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Do not contact contributors directly about support or help with technical issues.
@@ -249,6 +249,6 @@ OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.
This module is part of the `OCA/web <https://github.com/OCA/web/tree/12.0/web_widget_one2many_product_picker>`_ project on GitHub.
This module is part of the `OCA/web <https://github.com/OCA/web/tree/13.0/web_widget_one2many_product_picker>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

View File

@@ -4,14 +4,14 @@
{
"name": "Web Widget One2Many Product Picker",
"summary": "Widget to select products on one2many fields",
"version": "12.0.2.3.0",
"version": "13.0.1.0.0",
"category": "Website",
"author": "Tecnativa, " "Odoo Community Association (OCA)",
"website": "https://www.tecnativa.com",
"author": "Tecnativa, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/web",
"license": "AGPL-3",
"depends": ["product",],
"data": ["templates/assets.xml",],
"qweb": ["static/src/xml/one2many_product_picker.xml",],
"depends": ["product"],
"data": ["templates/assets.xml"],
"qweb": ["static/src/xml/one2many_product_picker.xml"],
"installable": True,
"auto_install": False,
}

View File

@@ -107,4 +107,3 @@ msgstr ""
#, python-format
msgid "[No widget %s]"
msgstr ""

View File

@@ -1,37 +1,21 @@
# Copyright 2020 Tecnativa - Alexandre D. Díaz
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl).
from odoo import api, fields, models, tools
from odoo import fields, models
class ProductProduct(models.Model):
_inherit = "product.product"
image_variant_medium = fields.Binary(
"Variant Image Medium (Computed)",
compute="_compute_variant_image",
"Variant Image Medium (Related)",
related="image_512",
help="This field holds the image used as image for the product variant"
"or product image medium, limited to 512x512px.",
)
image_variant_big = fields.Binary(
"Variant Image Big (Computed)",
compute="_compute_variant_image",
"Variant Image Big (Related)",
related="image_1024",
help="This field holds the image used as image for the product variant"
"or product image, limited to 1024x1024px.",
)
@api.depends("image_variant", "product_tmpl_id.image")
def _compute_variant_image(self):
for record in self:
if record.image_variant:
resized_images = tools.image_get_resized_images(
record.image_variant,
return_big=False,
return_small=False,
avoid_resize_medium=True,
)
record.image_variant_medium = resized_images["image_medium"]
record.image_variant_big = record.image_variant
else:
record.image_variant_medium = record.product_tmpl_id.image_medium
record.image_variant_big = record.product_tmpl_id.image

View File

@@ -367,7 +367,7 @@ ul.auto-toc {
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/web/tree/12.0/web_widget_one2many_product_picker"><img alt="OCA/web" src="https://img.shields.io/badge/github-OCA%2Fweb-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/web-12-0/web-12-0-web_widget_one2many_product_picker"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/162/12.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p>
<p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/web/tree/13.0/web_widget_one2many_product_picker"><img alt="OCA/web" src="https://img.shields.io/badge/github-OCA%2Fweb-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/web-13-0/web-13-0-web_widget_one2many_product_picker"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/162/13.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p>
<p>Adds the one2many_product_picker friendly mobile widget to create one2many lines linked with product.product records.</p>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
@@ -579,13 +579,13 @@ accept changes.</p>
<div class="section" id="parts-of-the-widget">
<h2><a class="toc-backref" href="#id8">Parts of the widget:</a></h2>
<blockquote>
<img alt="https://raw.githubusercontent.com/OCA/web/12.0/web_widget_one2many_product_picker/static/img/product_picker_anat.png" src="https://raw.githubusercontent.com/OCA/web/12.0/web_widget_one2many_product_picker/static/img/product_picker_anat.png" />
<img alt="https://raw.githubusercontent.com/OCA/web/13.0/web_widget_one2many_product_picker/static/img/product_picker_anat.png" src="https://raw.githubusercontent.com/OCA/web/13.0/web_widget_one2many_product_picker/static/img/product_picker_anat.png" />
</blockquote>
</div>
<div class="section" id="preview">
<h2><a class="toc-backref" href="#id9">Preview:</a></h2>
<blockquote>
<img alt="https://raw.githubusercontent.com/OCA/web/12.0/web_widget_one2many_product_picker/static/img/product_picker.gif" src="https://raw.githubusercontent.com/OCA/web/12.0/web_widget_one2many_product_picker/static/img/product_picker.gif" />
<img alt="https://raw.githubusercontent.com/OCA/web/13.0/web_widget_one2many_product_picker/static/img/product_picker.gif" src="https://raw.githubusercontent.com/OCA/web/13.0/web_widget_one2many_product_picker/static/img/product_picker.gif" />
</blockquote>
</div>
</div>
@@ -601,7 +601,7 @@ accept changes.</p>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/web/issues">GitHub Issues</a>.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed
<a class="reference external" href="https://github.com/OCA/web/issues/new?body=module:%20web_widget_one2many_product_picker%0Aversion:%2012.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<a class="reference external" href="https://github.com/OCA/web/issues/new?body=module:%20web_widget_one2many_product_picker%0Aversion:%2013.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
@@ -633,7 +633,7 @@ If you spotted it first, help us smashing it by providing a detailed and welcome
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.</p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/web/tree/12.0/web_widget_one2many_product_picker">OCA/web</a> project on GitHub.</p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/web/tree/13.0/web_widget_one2many_product_picker">OCA/web</a> project on GitHub.</p>
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
</div>
</div>

View File

@@ -3,7 +3,7 @@
odoo.define("web_widget_one2many_product_picker.tools", function(require) {
"use strict";
var field_utils = require("web.field_utils");
const field_utils = require("web.field_utils");
/**
* Calculate the price with discount

View File

@@ -1,3 +1,4 @@
/* global py */
// Copyright 2020 Tecnativa - Alexandre Díaz
// License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
odoo.define("web_widget_one2many_product_picker.ProductPickerQuickCreateForm", function(
@@ -5,18 +6,18 @@ odoo.define("web_widget_one2many_product_picker.ProductPickerQuickCreateForm", f
) {
"use strict";
var core = require("web.core");
var Widget = require("web.Widget");
var widgetRegistry = require("web.widget_registry");
var ProductPickerQuickCreateFormView = require("web_widget_one2many_product_picker.ProductPickerQuickCreateFormView")
const core = require("web.core");
const Widget = require("web.Widget");
const widgetRegistry = require("web.widget_registry");
const ProductPickerQuickCreateFormView = require("web_widget_one2many_product_picker.ProductPickerQuickCreateFormView")
.ProductPickerQuickCreateFormView;
var qweb = core.qweb;
const qweb = core.qweb;
/**
* This widget render a Form. Used by FieldOne2ManyProductPicker
*/
var ProductPickerQuickCreateForm = Widget.extend({
const ProductPickerQuickCreateForm = Widget.extend({
className: "oe_one2many_product_picker_quick_create",
xmlDependencies: [
"/web_widget_one2many_product_picker/static/src/xml/one2many_product_picker_quick_create.xml",
@@ -50,10 +51,9 @@ odoo.define("web_widget_one2many_product_picker.ProductPickerQuickCreateForm", f
* @override
*/
start: function() {
var self = this;
var def1 = this._super.apply(this, arguments);
var form_arch = this._generateFormArch();
var fieldsView = {
const def1 = this._super.apply(this, arguments);
const form_arch = this._generateFormArch();
const fieldsView = {
arch: form_arch,
fields: this.fields,
viewFields: this.fields,
@@ -62,11 +62,11 @@ odoo.define("web_widget_one2many_product_picker.ProductPickerQuickCreateForm", f
model: this.basicFieldParams.field.relation,
};
var node_context = this.node.attr("context") || "{}";
const node_context = this.node.attr("context") || "{}";
this.nodeContext = py.eval(node_context, {
active_id: this.res_id || false,
});
var refinedContext = _.extend(
const refinedContext = _.extend(
{},
this.main_state.getContext(),
this.nodeContext
@@ -92,13 +92,13 @@ odoo.define("web_widget_one2many_product_picker.ProductPickerQuickCreateForm", f
// If (this.id) {
// this.basicFieldParams.model.save(this.id, {savePoint: true});
// }
var def2 = this.formView.getController(this).then(function(controller) {
self.controller = controller;
self.$el.empty();
self.controller.appendTo(self.$el);
const def2 = this.formView.getController(this).then(controller => {
this.controller = controller;
this.$el.empty();
this.controller.appendTo(this.$el);
});
return $.when(def1, def2);
return Promise.all([def1, def2]);
},
on_attach_callback: function() {
@@ -112,7 +112,7 @@ odoo.define("web_widget_one2many_product_picker.ProductPickerQuickCreateForm", f
* @returns {String}
*/
_generateFormArch: function() {
var template =
let template =
"<templates><t t-name='One2ManyProductPicker.QuickCreateForm'>";
template += this.basicFieldParams.field.views.form.arch;
template += "</t></templates>";
@@ -140,21 +140,20 @@ odoo.define("web_widget_one2many_product_picker.ProductPickerQuickCreateForm", f
this.id = evt.data.baseRecordID;
this.start();
} else {
var self = this;
this.getParent()
._generateVirtualState({}, this.editContext)
.then(function(state) {
var data = {};
data[self.compareKey] = {
.then(state => {
const data = {};
data[this.compareKey] = {
operation: "ADD",
id: evt.data.compareValue,
};
self.basicFieldParams.model
this.basicFieldParams.model
._applyChange(state.id, data)
.then(function() {
self.res_id = state.res_id;
self.id = state.id;
self.start();
.then(() => {
this.res_id = state.res_id;
this.id = state.id;
this.start();
});
});
}

View File

@@ -10,20 +10,19 @@ odoo.define(
* is used by the RecordQuickCreate in One2ManyProductPicker views.
*/
var QuickCreateFormView = require("web.QuickCreateFormView");
var BasicModel = require("web.BasicModel");
var core = require("web.core");
const QuickCreateFormView = require("web.QuickCreateFormView");
const BasicModel = require("web.BasicModel");
const core = require("web.core");
var qweb = core.qweb;
const qweb = core.qweb;
BasicModel.include({
_applyOnChange: function(values, record, viewType) {
var vt = viewType || record.viewType;
// Ignore changes by record context 'ignore_onchanges' fields
if ("ignore_onchanges" in record.context) {
var ignore_changes = record.context.ignore_onchanges;
for (var index in ignore_changes) {
var field_name = ignore_changes[index];
const ignore_changes = record.context.ignore_onchanges;
for (const index in ignore_changes) {
const field_name = ignore_changes[index];
delete values[field_name];
}
delete record.context.ignore_onchanges;
@@ -32,7 +31,7 @@ odoo.define(
},
});
var ProductPickerQuickCreateFormRenderer = QuickCreateFormView.prototype.config.Renderer.extend(
const ProductPickerQuickCreateFormRenderer = QuickCreateFormView.prototype.config.Renderer.extend(
{
/**
* @override
@@ -46,7 +45,7 @@ odoo.define(
}
);
var ProductPickerQuickCreateFormController = QuickCreateFormView.prototype.config.Controller.extend(
const ProductPickerQuickCreateFormController = QuickCreateFormView.prototype.config.Controller.extend(
{
events: _.extend({}, QuickCreateFormView.prototype.events, {
"click .oe_record_add": "_onClickAdd",
@@ -67,14 +66,14 @@ odoo.define(
* Create or accept changes
*/
auto: function() {
var record = this.model.get(this.handle);
const record = this.model.get(this.handle);
if (
record.context.has_changes_confirmed ||
typeof record.context.has_changes_confirmed === "undefined"
) {
return;
}
var state = this._getRecordState();
const state = this._getRecordState();
if (state === "new") {
this._add();
} else if (state === "dirty") {
@@ -87,18 +86,20 @@ odoo.define(
* - record: Normal
* - new: Is a new record
* - dirty: Has changes
*
* @returns {Object}
*/
_getRecordState: function() {
var record = this.model.get(this.handle);
var state = "record";
const record = this.model.get(this.handle);
let state = "record";
if (this.model.isNew(record.id)) {
state = "new";
} else if (record.isDirty()) {
state = "dirty";
}
if (state === "new") {
for (var index in this.mainRecordData.data) {
var recordData = this.mainRecordData.data[index];
for (const index in this.mainRecordData.data) {
const recordData = this.mainRecordData.data[index];
if (recordData.ref === record.ref) {
if (record.isDirty()) {
state = "dirty";
@@ -160,12 +161,12 @@ odoo.define(
/**
* @private
* @param {Array[String]} fields_changed
* @param {Array} fields_changed
* @returns {Boolean}
*/
_needReloadCard: function(fields_changed) {
for (var index in fields_changed) {
var field = fields_changed[index];
for (const index in fields_changed) {
const field = fields_changed[index];
if (field === this.fieldMap[this.compareKey]) {
return true;
}
@@ -182,33 +183,33 @@ odoo.define(
* @param {ChangeEvent} ev
*/
_onFieldChanged: function(ev) {
var fields_changed = Object.keys(ev.data.changes);
const fields_changed = Object.keys(ev.data.changes);
if (this._needReloadCard(fields_changed)) {
var field = ev.data.changes[fields_changed[0]];
var new_value = false;
const field = ev.data.changes[fields_changed[0]];
let new_value = false;
if (typeof field === "object") {
new_value = field.id;
} else {
new_value = field;
}
var reload_values = {
const reload_values = {
compareValue: new_value,
};
var record = this.model.get(this.handle);
if (!("base_record_id" in record.context)) {
var old_value = record.data[this.compareKey];
const record = this.model.get(this.handle);
if ("base_record_id" in record.context) {
reload_values.baseRecordID = record.context.base_record_id;
reload_values.baseRecordResID =
record.context.base_record_res_id;
reload_values.baseRecordCompareValue =
record.context.base_record_compare_value;
} else {
let old_value = record.data[this.compareKey];
if (typeof old_value === "object") {
old_value = old_value.data.id;
}
reload_values.baseRecordID = record.id;
reload_values.baseRecordResID = record.ref;
reload_values.baseRecordCompareValue = old_value;
} else {
reload_values.baseRecordID = record.context.base_record_id;
reload_values.baseRecordResID =
record.context.base_record_res_id;
reload_values.baseRecordCompareValue =
record.context.base_record_compare_value;
}
this.trigger_up("reload_view", reload_values);
@@ -237,28 +238,30 @@ odoo.define(
_add: function() {
if (this._disabled) {
// Don't do anything if we are already creating a record
return $.Deferred();
return Promise.resolve();
}
this.model.updateRecordContext(this.handle, {
has_changes_confirmed: true,
});
var self = this;
this._disableQuickCreate();
return this.saveRecord(this.handle, {
stayInEdit: true,
reload: true,
savePoint: true,
viewType: "form",
}).then(function() {
var record = self.model.get(self.handle);
self.trigger_up("restore_flip_card", {
success_callback: function() {
self.trigger_up("create_quick_record", {
}).then(() => {
const record = this.model.get(this.handle);
this.model.updateRecordContext(this.handle, {saving: true});
this.trigger_up("restore_flip_card", {
success_callback: () => {
this.trigger_up("create_quick_record", {
id: record.id,
callback: () => {
this.model.unsetDirty(this.handle);
// Self._updateButtons();
this._enableQuickCreate();
},
});
self.model.unsetDirty(self.handle);
// Self._updateButtons();
self._enableQuickCreate();
},
block: true,
});
@@ -267,51 +270,51 @@ odoo.define(
_remove: function() {
if (this._disabled) {
// Don't do anything if we are already creating a record
return $.Deferred();
return Promise.resolve();
}
this._disableQuickCreate();
this.trigger_up("restore_flip_card", {block: true});
var record = this.model.get(this.handle);
const record = this.model.get(this.handle);
this.trigger_up("list_record_remove", {
id: record.id,
});
},
_change: function() {
var self = this;
const self = this;
if (this._disabled) {
// Don't do anything if we are already creating a record
return $.Deferred();
return Promise.resolve();
}
this._disableQuickCreate();
this.model.updateRecordContext(this.handle, {
has_changes_confirmed: true,
});
var record = this.model.get(this.handle);
const record = this.model.get(this.handle);
this.trigger_up("restore_flip_card", {
success_callback: function() {
self.trigger_up("update_quick_record", {
id: record.id,
callback: function() {
self.model.unsetDirty(self.handle);
// Self._updateButtons();
self._enableQuickCreate();
},
});
self.model.unsetDirty(self.handle);
// Self._updateButtons();
self._enableQuickCreate();
},
block: true,
});
},
_discard: function() {
var self = this;
if (this._disabled) {
// Don't do anything if we are already creating a record
return $.Deferred();
return Promise.resolve();
}
this._disableQuickCreate();
var record = this.model.get(this.handle);
const record = this.model.get(this.handle);
this.model.discardChanges(this.handle, {
rollback: true,
});
@@ -324,11 +327,11 @@ odoo.define(
this._updateButtons();
this._enableQuickCreate();
} else {
this.update({}, {reload: false}).then(function() {
self.model.unsetDirty(self.handle);
self.trigger_up("restore_flip_card");
self._updateButtons();
self._enableQuickCreate();
this.update({}, {reload: false}).then(() => {
this.model.unsetDirty(this.handle);
this.trigger_up("restore_flip_card");
this._updateButtons();
this._enableQuickCreate();
});
}
},
@@ -371,7 +374,7 @@ odoo.define(
}
);
var ProductPickerQuickCreateFormView = QuickCreateFormView.extend({
const ProductPickerQuickCreateFormView = QuickCreateFormView.extend({
config: _.extend({}, QuickCreateFormView.prototype.config, {
Renderer: ProductPickerQuickCreateFormRenderer,
Controller: ProductPickerQuickCreateFormController,

View File

@@ -5,21 +5,25 @@ odoo.define(
function(require) {
"use strict";
var core = require("web.core");
var Widget = require("web.Widget");
var ProductPickerQuickModifPriceFormView = require("web_widget_one2many_product_picker.ProductPickerQuickModifPriceFormView")
const core = require("web.core");
const Widget = require("web.Widget");
const ProductPickerQuickModifPriceFormView = require("web_widget_one2many_product_picker.ProductPickerQuickModifPriceFormView")
.ProductPickerQuickModifPriceFormView;
var qweb = core.qweb;
const qweb = core.qweb;
/**
* This widget render a Form. Used by FieldOne2ManyProductPicker
*/
var ProductPickerQuickModifPriceForm = Widget.extend({
const ProductPickerQuickModifPriceForm = Widget.extend({
className: "oe_one2many_product_picker_quick_modif_price",
xmlDependencies: [
"/web_widget_one2many_product_picker/static/src/xml/one2many_product_picker_quick_modif_price.xml",
],
events: {
"click .oe_record_change": "_onClickChange",
"click .oe_record_discard": "_onClickDiscard",
},
/**
* @override
@@ -47,9 +51,8 @@ odoo.define(
* @override
*/
start: function() {
var self = this;
var def1 = this._super.apply(this, arguments);
var fieldsView = {
const def1 = this._super.apply(this, arguments);
const fieldsView = {
arch: this._generateFormArch(),
fields: this.fields,
viewFields: this.fields,
@@ -78,19 +81,21 @@ odoo.define(
if (this.id) {
this.basicFieldParams.model.save(this.id, {savePoint: true});
}
var def2 = this.formView.getController(this).then(function(controller) {
self.controller = controller;
self.$el.empty();
self.controller.appendTo(self.$el);
const def2 = this.formView.getController(this).then(controller => {
this.controller = controller;
this.$(".modal-body").empty();
this.controller.appendTo(this.$(".modal-body"));
this.$el.on("hidden.bs.modal", this._onModalHidden.bind(this));
});
return $.when(def1, def2);
return Promise.all([def1, def2]);
},
/**
* @override
*/
destroy: function() {
this.$el.off("hidden.bs.modal");
this._super.apply(this, arguments);
},
@@ -103,31 +108,33 @@ odoo.define(
* @returns {String}
*/
_generateFormArch: function() {
var wanted_field_states = this._getWantedFieldState();
var template =
const wanted_field_states = this._getWantedFieldState();
let template =
"<templates><t t-name='One2ManyProductPicker.QuickModifPrice.Form'>";
template += this.basicFieldParams.field.views.form.arch;
template += "</t></templates>";
qweb.add_template(template);
var $arch = $(
const $arch = $(
qweb.render("One2ManyProductPicker.QuickModifPrice.Form", {
field_map: this.fieldMap,
record_search: this.searchRecord,
})
);
var field_names = Object.keys(wanted_field_states);
var gen_arch = "<form><group>";
for (var index in field_names) {
var field_name = field_names[index];
var $field = $arch.find("field[name='" + field_name + "']");
var modifiers = $field.attr("modifiers")
const field_names = Object.keys(
this.basicFieldParams.field.views.form.fields
);
let gen_arch = "<form><group>";
for (const index in field_names) {
const field_name = field_names[index];
const $field = $arch.find("field[name='" + field_name + "']");
const modifiers = $field.attr("modifiers")
? JSON.parse($field.attr("modifiers"))
: {};
modifiers.invisible = false;
modifiers.invisible = !(field_name in wanted_field_states);
modifiers.readonly = wanted_field_states[field_name];
$field.attr("modifiers", JSON.stringify(modifiers));
$field.attr("invisible", "0");
$field.attr("invisible", modifiers.invisible ? "1" : "0");
$field.attr(
"readonly",
wanted_field_states[field_name] ? "1" : "0"
@@ -146,11 +153,95 @@ odoo.define(
* @returns {Object}
*/
_getWantedFieldState: function() {
var wantedFieldState = {};
const wantedFieldState = {};
wantedFieldState[this.fieldMap.discount] = !this.canEditDiscount;
wantedFieldState[this.fieldMap.price_unit] = !this.canEditPrice;
return wantedFieldState;
},
/**
* @private
*/
_onModalHidden: function() {
this.destroy();
},
/**
* @private
* @param {MouseEvent} ev
*/
_onClickChange: function(ev) {
ev.stopPropagation();
const model = this.basicFieldParams.model;
model.updateRecordContext(this.id, {
has_changes_confirmed: true,
});
const is_virtual = model.isPureVirtual(this.id);
// If is a 'pure virtual' record, save it in the selected list
if (is_virtual) {
if (model.isDirty(this.id)) {
this._disableQuickCreate();
this.controller
.saveRecord(this.id, {
stayInEdit: true,
reload: true,
savePoint: true,
viewType: "form",
})
.then(() => {
this._enableQuickCreate();
model.unsetDirty(this.id);
this.trigger_up("create_quick_record", {
id: this.id,
});
});
}
} else {
// If is a "normal" record, update it
this.trigger_up("update_quick_record", {
id: this.id,
});
model.unsetDirty(this.id);
}
},
/**
* @private
* @param {MouseEvent} ev
*/
_onClickDiscard: function(ev) {
ev.stopPropagation();
const model = this.basicFieldParams.model;
model.discardChanges(this.id, {
rollback: true,
});
this.trigger_up("update_quick_record", {
id: this.id,
});
},
/**
* @private
*/
_disableQuickCreate: function() {
// Ensures that the record won't be created twice
this.$el.addClass("o_disabled");
this.$("input:not(:disabled),button:not(:disabled)")
.addClass("o_temporarily_disabled")
.attr("disabled", "disabled");
},
/**
* @private
*/
_enableQuickCreate: function() {
// Allows to create again
this.$el.removeClass("o_disabled");
this.$("input.o_temporarily_disabled,button.o_temporarily_disabled")
.removeClass("o_temporarily_disabled")
.attr("disabled", false);
},
});
return ProductPickerQuickModifPriceForm;

View File

@@ -10,43 +10,26 @@ odoo.define(
* is used by the RecordQuickCreate in One2ManyProductPicker views.
*/
var QuickCreateFormView = require("web.QuickCreateFormView");
var core = require("web.core");
var tools = require("web_widget_one2many_product_picker.tools");
const QuickCreateFormView = require("web.QuickCreateFormView");
const core = require("web.core");
const tools = require("web_widget_one2many_product_picker.tools");
var qweb = core.qweb;
const qweb = core.qweb;
var ProductPickerQuickModifPriceFormRenderer = QuickCreateFormView.prototype.config.Renderer.extend(
const ProductPickerQuickModifPriceFormRenderer = QuickCreateFormView.prototype.config.Renderer.extend(
{
/**
* @override
*/
start: function() {
var self = this;
this.$el.addClass(
"oe_one2many_product_picker_form_view o_xxs_form_view"
);
return this._super.apply(this, arguments).then(function() {
self._appendPrice();
self._appendButtons();
return this._super.apply(this, arguments).then(() => {
this._appendPrice();
});
},
/**
* @private
*/
_appendButtons: function() {
this.$el.find(".oe_one2many_product_picker_form_buttons").remove();
this.$el.append(
qweb.render(
"One2ManyProductPicker.QuickModifPrice.FormButtons",
{
mode: this.mode,
}
)
);
},
/**
* @private
*/
@@ -59,13 +42,8 @@ odoo.define(
}
);
var ProductPickerQuickModifPriceFormController = QuickCreateFormView.prototype.config.Controller.extend(
const ProductPickerQuickModifPriceFormController = QuickCreateFormView.prototype.config.Controller.extend(
{
events: _.extend({}, QuickCreateFormView.prototype.events, {
"click .oe_record_change": "_onClickChange",
"click .oe_record_discard": "_onClickDiscard",
}),
/**
* @override
*/
@@ -81,28 +59,29 @@ odoo.define(
* @override
*/
start: function() {
var self = this;
return this._super.apply(this, arguments).then(function() {
self._updatePrice();
return this._super.apply(this, arguments).then(() => {
const record = this.model.get(this.handle);
this._updatePrice(record.data);
});
},
/**
* @override
*/
_onFieldChanged: function() {
_onFieldChanged: function(ev) {
this._super.apply(this, arguments);
this._updatePrice();
const record = this.model.get(this.handle);
this._updatePrice(_.extend({}, record.data, ev.data.changes));
},
/**
* @private
* @param {Object} values
*/
_updatePrice: function() {
var record = this.model.get(this.handle);
var price_reduce = tools.priceReduce(
record.data[this.fieldMap.price_unit],
record.data[this.fieldMap.discount]
_updatePrice: function(values) {
const price_reduce = tools.priceReduce(
values[this.fieldMap.price_unit],
values[this.fieldMap.discount]
);
this.renderer.$el
.find(".oe_price")
@@ -111,98 +90,14 @@ odoo.define(
price_reduce,
this.getParent().state.fields[this.fieldMap.price_unit],
this.currencyField,
record
values
)
);
},
/**
* @private
*/
_disableQuickCreate: function() {
// Ensures that the record won't be created twice
this._disabled = true;
this.$el.addClass("o_disabled");
this.$("input:not(:disabled)")
.addClass("o_temporarily_disabled")
.attr("disabled", "disabled");
},
/**
* @private
*/
_enableQuickCreate: function() {
// Allows to create again
this._disabled = false;
this.$el.removeClass("o_disabled");
this.$("input.o_temporarily_disabled")
.removeClass("o_temporarily_disabled")
.attr("disabled", false);
},
/**
* @private
* @param {MouseEvent} ev
*/
_onClickChange: function(ev) {
var self = this;
ev.stopPropagation();
this.model.updateRecordContext(this.handle, {
has_changes_confirmed: true,
});
var is_virtual = this.model.isPureVirtual(this.handle);
// If is a 'pure virtual' record, save it in the selected list
if (is_virtual) {
if (this.model.isDirty(this.handle)) {
this._disableQuickCreate();
this.saveRecord(this.handle, {
stayInEdit: true,
reload: true,
savePoint: true,
viewType: "form",
}).then(function() {
self._enableQuickCreate();
var record = self.model.get(self.handle);
self.model.unsetDirty(self.handle);
self.trigger_up("create_quick_record", {
id: record.id,
});
self.getParent().destroy();
});
} else {
this.getParent().destroy();
}
} else {
// If is a "normal" record, update it
var record = this.model.get(this.handle);
this.trigger_up("update_quick_record", {
id: record.id,
});
self.model.unsetDirty(self.handle);
this.getParent().destroy();
}
},
/**
* @private
* @param {MouseEvent} ev
*/
_onClickDiscard: function(ev) {
ev.stopPropagation();
this.model.discardChanges(this.handle, {
rollback: true,
});
var record = this.model.get(this.handle);
this.trigger_up("update_quick_record", {
id: record.id,
});
this.getParent().destroy();
},
}
);
var ProductPickerQuickModifPriceFormView = QuickCreateFormView.extend({
const ProductPickerQuickModifPriceFormView = QuickCreateFormView.extend({
config: _.extend({}, QuickCreateFormView.prototype.config, {
Renderer: ProductPickerQuickModifPriceFormRenderer,
Controller: ProductPickerQuickModifPriceFormController,

View File

@@ -6,19 +6,19 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
) {
"use strict";
var core = require("web.core");
var Widget = require("web.Widget");
var Domain = require("web.Domain");
var widgetRegistry = require("web.widget_registry");
var tools = require("web_widget_one2many_product_picker.tools");
var ProductPickerQuickModifPriceForm = require("web_widget_one2many_product_picker.ProductPickerQuickModifPriceForm");
var FieldManagerMixin = require("web.FieldManagerMixin");
const core = require("web.core");
const Widget = require("web.Widget");
const Domain = require("web.Domain");
const widgetRegistry = require("web.widget_registry");
const tools = require("web_widget_one2many_product_picker.tools");
const ProductPickerQuickModifPriceForm = require("web_widget_one2many_product_picker.ProductPickerQuickModifPriceForm");
const config = require("web.config");
var qweb = core.qweb;
var _t = core._t;
const qweb = core.qweb;
const _t = core._t;
/* This represent a record (a card) */
var One2ManyProductPickerRecord = Widget.extend({
const One2ManyProductPickerRecord = Widget.extend({
custom_events: {
quick_record_updated: "_onQuickRecordUpdated",
restore_flip_card: "_onRestoreFlipCard",
@@ -80,6 +80,7 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
* @override
*/
destroy: function() {
this.$el.remove();
this.$card.off("");
this._super.apply(this, arguments);
},
@@ -101,16 +102,19 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
* new one.
*
* @param {Object} state
* @returns {Promise}
*/
recreate: function(state) {
if (state) {
this._setState(state);
}
this.$card.removeClass("blocked");
// Avoid recreate active record
if (this.$card.hasClass("active")) {
this._processDynamicFields();
return $.when();
if (this.$card) {
this.$card.removeClass("blocked");
// Avoid recreate active record
if (this.$card.hasClass("active")) {
this._processDynamicFields();
return $.when();
}
}
this.on_detach_callback();
@@ -138,10 +142,11 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
*
* @private
* @param {String} price_field
* @returns {String}
*/
_getMonetaryFieldValue: function(price_field) {
var field_name = this.options.fieldMap[price_field];
var price = this.state.data[field_name];
const field_name = this.options.fieldMap[price_field];
const price = this.state.data[field_name];
return tools.monetary(
price,
this.state.fields[field_name],
@@ -184,9 +189,20 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
if (recordSearch) {
this.recordSearch = recordSearch;
}
var model = this.options.basicFieldParams.model;
const model = this.options.basicFieldParams.model;
this.is_virtual =
(this.state && model.isPureVirtual(this.state.id)) || false;
// Check if has cached qty
if (this.state && this.state.id) {
const record = model.get(this.state.id);
const lazy_qty = (record && record.context.lazy_qty) || 0;
if (lazy_qty) {
model.updateRecordContext(this.state.id, {lazy_qty: 0});
// Record already has 1
this._incProductQty(lazy_qty - 1);
}
}
},
/**
@@ -197,8 +213,8 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
// Using directly the 'model record' instead of the state because
// the state it's a parsed version of this record that doesn't
// contains the '_virtual' attribute.
var model = this.options.basicFieldParams.model;
var record = model.get(this.state.id);
const model = this.options.basicFieldParams.model;
const record = model.get(this.state.id);
return {
record_search: this.recordSearch,
user_context:
@@ -214,6 +230,8 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
modified: record && record.context.product_picker_modified,
active_model: "",
auto_save: this.options.autoSave,
is_saving: record && record.context.saving,
lazy_qty: record && record.context.lazy_qty,
};
},
@@ -224,7 +242,7 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
* @returns {Object}
*/
_getInternalVirtualRecordContext: function() {
var context = {};
const context = {};
context["default_" + this.options.basicFieldParams.relation_field] =
this.options.basicFieldParams.state.id || null;
return context;
@@ -238,7 +256,7 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
* @returns {Object}
*/
_getInternalVirtualRecordData: function() {
var data = {};
const data = {};
data[this.options.fieldMap.product] = {
operation: "ADD",
id: this.recordSearch.id,
@@ -253,15 +271,15 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
* @returns {Object}
*/
_generateVirtualState: function(data, context) {
var model = this.options.basicFieldParams.model;
var scontext = _.extend(
const model = this.options.basicFieldParams.model;
const scontext = _.extend(
{},
this._getInternalVirtualRecordContext(),
context
);
// Force qty to 1.0 to launch correct onchanges
scontext[`default_${this.options.fieldMap.product_uom_qty}`] = 1.0;
var sdata = _.extend({}, this._getInternalVirtualRecordData(), data);
const sdata = _.extend({}, this._getInternalVirtualRecordData(), data);
return model.createVirtualRecord(this.options.basicFieldParams.value.id, {
data: sdata,
context: scontext,
@@ -303,33 +321,32 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
* @private
* @param {jQueryElement} $container
*/
_processWidgetFields: function($container, widget_list) {
var self = this;
$container.find("field").each(function() {
var $field = $(this);
_processWidgetFields: function($container) {
$container.find("field").each((key, value) => {
const $field = $(value);
if ($field.parents("widget").length) {
return;
}
var field_name = $field.attr("name");
var field_widget = $field.attr("widget");
const field_name = $field.attr("name");
const field_widget = $field.attr("widget");
// A widget is specified for that field or a field is a many2many ;
// in this latest case, we want to display the widget many2manytags
// even if it is not specified in the view.
if (field_widget || self.fields[field_name].type === "many2many") {
var widget = self.subWidgets[field_name];
if (field_widget || this.fields[field_name].type === "many2many") {
let widget = this.subWidgets[field_name];
if (widget) {
// A widget already exists for that field, so reset it
// with the new state
widget.reset(self.state);
widget.reset(this.state);
$field.replaceWith(widget.$el);
} else {
// The widget doesn't exist yet, so instanciate it
var Widget = self.fieldsInfo[field_name].Widget;
const Widget = this.fieldsInfo[field_name].Widget;
if (Widget) {
widget = self._processWidget($field, field_name, Widget);
self.subWidgets[field_name] = widget;
} else if (config.debug) {
widget = this._processWidget($field, field_name, Widget);
this.subWidgets[field_name] = widget;
} else if (config.isDebug()) {
// The widget is not implemented
$field.replaceWith(
$("<span>", {
@@ -362,23 +379,26 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
// field's widgets point of view
// that dict being shared between records, we don't modify it
// in place
var attrs = Object.create(null);
_.each(this.fieldsInfo[field_name], function(value, key) {
const attrs = Object.create(null);
_.each(this.fieldsInfo[field_name], (value, key) => {
if (_.str.startsWith(key, "t-att-")) {
key = key.slice(6);
value = $field.attr(key);
}
attrs[key] = value;
});
var options = _.extend({}, this.options, {
const options = _.extend({}, this.options, {
attrs: attrs,
data: this.state.data,
});
var widget = new Widget(this, field_name, this.getParent().state, options);
var def = widget.replace($field);
if (def.state() === "pending") {
this.defs.push(def);
}
const widget = new Widget(
this,
field_name,
this.getParent().state,
options
);
const def = widget.replace($field);
this.defs.push(def);
return widget;
},
@@ -387,41 +407,45 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
*
* @private
* @param {jQueryElement} $container
* @param {String} widget_zone
*/
_processWidgets: function($container, widget_zone) {
var self = this;
$container.find("widget").each(function() {
var $field = $(this);
var FieldWidget = widgetRegistry.get($field.attr("name"));
var widget = new FieldWidget(self, {
fieldsInfo: self.fieldsInfo,
fields: self.fields,
main_state: self.getParent().state,
state: self.state,
fieldMap: self.options.fieldMap,
searchRecord: self.recordSearch,
$container.find("widget").each((key, value) => {
const $field = $(value);
const FieldWidget = widgetRegistry.get($field.attr("name"));
const widget = new FieldWidget(this, {
fieldsInfo: this.fieldsInfo,
fields: this.fields,
main_state: this.getParent().state,
state: this.state,
fieldMap: this.options.fieldMap,
searchRecord: this.recordSearch,
node: $field,
readonly: self.options.readOnlyMode,
basicFieldParams: self.options.basicFieldParams,
data: self.state && self.state.data,
readonly: this.options.readOnlyMode,
basicFieldParams: this.options.basicFieldParams,
data: this.state && this.state.data,
});
self.widgets[widget_zone].push(widget);
this.widgets[widget_zone].push(widget);
var def = widget
._widgetRenderAndInsert(function() {
const def = widget
._widgetRenderAndInsert(() => {
// Do nothing
})
.then(function() {
.then(() => {
widget.$el.addClass("o_widget");
$field.replaceWith(widget.$el);
});
if (def.state() === "pending") {
self.defs.push(def);
}
this.defs.push(def);
});
},
_updateLazyQty: function() {
var model = this.options.basicFieldParams.model;
var record = model.get(this.state.id);
this.$el.find(".lazy_product_qty").text(record.context.lazy_qty);
},
/**
* This is a special handle for display the non-fields.
* Similar 't-esc' behaviour.
@@ -436,38 +460,37 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
* text: 20 Items
*
* @private
* @param {Array[String]} fields
* @param {Array} fields
*/
_processDynamicFields: function(fields) {
if (!this.state) {
return;
}
var self = this;
var model = this.options.basicFieldParams.model;
var record = model.get(this.state.id);
var state_data = record.data;
const model = this.options.basicFieldParams.model;
const record = model.get(this.state.id);
const state_data = record.data;
var to_find = [];
let to_find = [];
if (!_.isEmpty(fields)) {
to_find = _.map(fields, function(field) {
to_find = _.map(fields, field => {
return _.str.sprintf("[data-field=%s]", [field]);
});
} else {
to_find = ["[data-field]"];
}
this.$el.find(to_find.join()).each(function() {
var $elm = $(this);
var format_out = $elm.data("esc") || $elm.data("field");
this.$el.find(to_find.join()).each((key, value) => {
const $elm = $(value);
const format_out = $elm.data("esc") || $elm.data("field");
$elm.html(
py.eval(format_out, _.extend({}, state_data, self.recordSearch))
py.eval(format_out, _.extend({}, state_data, this.recordSearch))
);
});
if (this.options.showDiscount) {
var field_map = this.options.fieldMap;
const field_map = this.options.fieldMap;
if (state_data) {
var has_discount = state_data[field_map.discount] > 0.0;
const has_discount = state_data[field_map.discount] > 0.0;
this.$el
.find(".original_price,.discount_price")
.toggleClass("d-none", !has_discount);
@@ -487,10 +510,10 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
* @returns {String}
*/
_calcPriceReduced: function() {
var price_reduce = 0;
var field_map = this.options.fieldMap;
var model = this.options.basicFieldParams.model;
var record = model.get(this.state.id);
let price_reduce = 0;
const field_map = this.options.fieldMap;
const model = this.options.basicFieldParams.model;
const record = model.get(this.state.id);
if (record && record.data[field_map.discount]) {
price_reduce = tools.priceReduce(
record.data[field_map.price_unit],
@@ -513,9 +536,10 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
* @returns {Promise}
*/
_saveRecord: function() {
var self = this;
var model = this.options.basicFieldParams.model;
var record = model.get(this.state.id);
const model = this.options.basicFieldParams.model;
const record = model.get(this.state.id);
model.updateRecordContext(this.state.id, {saving: true});
this.recreate();
return model
.save(record.id, {
stayInEdit: true,
@@ -523,17 +547,17 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
savePoint: true,
viewType: "form",
})
.then(function() {
var record = model.get(self.state.id);
self.trigger_up("create_quick_record", {
.then(() => {
const record = model.get(this.state.id);
this.trigger_up("create_quick_record", {
id: record.id,
callback: function() {
self.$card
callback: () => {
this.$card
.find(".o_catch_attention")
.removeClass("o_catch_attention");
},
});
model.unsetDirty(self.state.id);
model.unsetDirty(this.state.id);
});
},
@@ -541,13 +565,12 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
* @private
*/
_updateRecord: function() {
var self = this;
var model = this.options.basicFieldParams.model;
var record = model.get(this.state.id);
const model = this.options.basicFieldParams.model;
const record = model.get(this.state.id);
this.trigger_up("update_quick_record", {
id: record.id,
callback: function() {
self.$card
callback: () => {
this.$card
.find(".o_catch_attention")
.removeClass("o_catch_attention");
},
@@ -560,20 +583,23 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
* @returns {Promise}
*/
_addProduct: function() {
var self = this;
var model = this.options.basicFieldParams.model;
const model = this.options.basicFieldParams.model;
model.updateRecordContext(this.state.id, {
ignore_warning: this.options.ignoreWarning,
});
var record = model.get(this.state.id);
var changes = _.pick(record.data, this.options.fieldMap.product_uom_qty);
const record = model.get(this.state.id);
// Because we don't hide the 'add' button when the product is added form back form
// we check if the record is in "saving" mode to prevent duplicate it.
if (record.context.saving) {
return Promise.resolve();
}
const changes = _.pick(record.data, this.options.fieldMap.product_uom_qty);
if (changes[this.options.fieldMap.product_uom_qty] === 0) {
changes[this.options.fieldMap.product_uom_qty] = 1;
}
var model = this.options.basicFieldParams.model;
this.$card.addClass("blocked");
return model.notifyChanges(record.id, changes).then(function() {
self._saveRecord();
return model.notifyChanges(record.id, changes).then(() => {
this._saveRecord();
});
},
@@ -583,45 +609,54 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
* @returns {Promise}
*/
_incProductQty: function(amount) {
var self = this;
var model = this.options.basicFieldParams.model;
const model = this.options.basicFieldParams.model;
model.updateRecordContext(this.state.id, {
ignore_warning: this.options.ignoreWarning,
});
var record = model.get(this.state.id);
var changes = _.pick(record.data, this.options.fieldMap.product_uom_qty);
changes[this.options.fieldMap.product_uom_qty] += amount;
return model.notifyChanges(record.id, changes).then(function() {
self._processDynamicFields();
self._lazyUpdateRecord();
});
const record = model.get(this.state.id);
if (this.options.autoSave && !this.state.data.id) {
let lazy_qty = record.context.lazy_qty || 1;
lazy_qty += amount;
model.updateRecordContext(this.state.id, {lazy_qty: lazy_qty});
this._updateLazyQty();
} else {
// HACK: Modify the raw state value to show correct 'qty' when
// receive the response from Odoo. This happens because the widget
// sends a creation with qty 1 but can still add more qty mean while
// wait for the Odoo response.
const model_record_data = model.localData[this.state.id].data;
model_record_data[this.options.fieldMap.product_uom_qty] += amount;
return model
.notifyChanges(record.id, {
[this.options.fieldMap.product_uom_qty]:
model_record_data[this.options.fieldMap.product_uom_qty],
})
.then(() => {
this._processDynamicFields();
this._lazyUpdateRecord();
});
}
},
/**
* @private
* @param {Selector/HTMLElement} target
*/
_doInteractAnim: function(target, currentTarget) {
var $target = $(target);
var $currentTarget = $(currentTarget);
var $img = $currentTarget.find(".oe_flip_card_front img");
_doInteractAnim: function(target) {
const $target = $(target);
$target.addClass("o_catch_attention");
$img.addClass("oe_product_picker_catch_attention");
$img.on("animationend", function() {
$img.removeClass("oe_product_picker_catch_attention");
$img.off("animationend");
});
},
/**
* @private
*/
_openPriceModifier: function() {
var state_data = this.state && this.state.data;
const state_data = this.state && this.state.data;
if (this.options.readOnlyMode || !state_data) {
return;
}
var modif_price_form = new ProductPickerQuickModifPriceForm(this, {
const modif_price_form = new ProductPickerQuickModifPriceForm(this, {
fieldsInfo: this.fieldsInfo,
fields: this.fields,
main_state: this.getParent().state,
@@ -634,11 +669,12 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
canEditDiscount: this.options.editDiscount,
currencyField: this.options.currencyField,
});
this.$modifPricePopup = $(
qweb.render("One2ManyProductPicker.QuickModifPricePopup")
this.$modifPriceModal = $(
qweb.render("One2ManyProductPicker.QuickModifPrice.Modal")
);
this.$modifPricePopup.appendTo($(".o_main_content"));
modif_price_form.attachTo(this.$modifPricePopup);
this.$modifPriceModal.appendTo($(".oe_one2many_product_picker_view"));
modif_price_form.attachTo(this.$modifPriceModal);
this.$modifPriceModal.modal();
},
// HANDLE EVENTS
@@ -649,13 +685,10 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
*/
_onClickFlipCard: function(evt) {
// Avoid clicks on form elements
if (
["INPUT", "BUTTON", "A"].indexOf(evt.target.tagName) !== -1 ||
this.$card.hasClass("blocked")
) {
if (["INPUT", "BUTTON", "A"].indexOf(evt.target.tagName) !== -1) {
return;
}
var $target = $(evt.target);
const $target = $(evt.target);
if (!this.options.readOnlyMode) {
if (
$target.hasClass("add_product") ||
@@ -664,7 +697,7 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
if (!this.is_adding_product) {
this.is_adding_product = true;
this._addProduct();
this._doInteractAnim(evt.target, evt.currentTarget);
this._doInteractAnim(evt.target);
}
return;
} else if (
@@ -672,13 +705,18 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
$target.parents(".product_qty").length
) {
this._incProductQty(1);
this._doInteractAnim(evt.target, evt.currentTarget);
this._doInteractAnim(evt.target);
return;
} else if ($target.hasClass("safezone")) {
// Do nothing on safe zones
return;
}
}
if (this.$card.hasClass("blocked")) {
return;
}
if (!this._clickFlipCardDelayed) {
this._clickFlipCardDelayed = setTimeout(
this._onClickDelayedFlipCard.bind(this, evt),
@@ -708,24 +746,23 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
this.$card.removeClass("active");
this.$front.removeClass("d-none");
} else {
var self = this;
this.defs = [];
if (!this.widgets.back.length) {
this._processWidgetFields(this.$back);
this._processWidgets(this.$back, "back");
}
this._processDynamicFields();
$.when(this.defs).then(function() {
var $actived_card = self.$el.parent().find(".active");
$.when(this.defs).then(() => {
const $actived_card = this.$el.parent().find(".active");
$actived_card.removeClass("active");
$actived_card.find(".oe_flip_card_front").removeClass("d-none");
self.$card.addClass("active");
self.$card.on("transitionend", function() {
self.$front.addClass("d-none");
self.$card.off("transitionend");
this.$card.addClass("active");
this.$card.on("transitionend", () => {
this.$front.addClass("d-none");
this.$card.off("transitionend");
});
self.trigger_up("record_flip", {
widget_index: self.$el.data("renderer_widget_index"),
this.trigger_up("record_flip", {
widget_index: this.$el.data("renderer_widget_index"),
prev_widget_index: $actived_card
.parent()
.data("renderer_widget_index"),
@@ -739,16 +776,16 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
* @param {MouseEvent} evt
*/
_onDblClickDelayedFlipCard: function(evt) {
var $target = $(evt.target);
const $target = $(evt.target);
if (
$target.hasClass("badge_price") ||
$target.parents(".badge_price").length
) {
this._openPriceModifier();
} else {
var $currentTarget = $(evt.currentTarget);
var $img = $currentTarget.find(".oe_flip_card_front img");
var cur_img_src = $img.attr("src");
const $currentTarget = $(evt.currentTarget);
const $img = $currentTarget.find(".oe_flip_card_front img");
const cur_img_src = $img.attr("src");
if ($currentTarget.hasClass("oe_flip_card_maximized")) {
$currentTarget.removeClass("oe_flip_card_maximized");
$currentTarget.on("transitionend", function() {
@@ -763,12 +800,12 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
$currentTarget.off("transitionend");
});
} else {
var $actived_card = this.$el.parent().find(".active");
const $actived_card = this.$el.parent().find(".active");
if ($actived_card[0] !== $currentTarget[0]) {
$actived_card.removeClass("active");
$actived_card.find(".oe_flip_card_front").removeClass("d-none");
}
var offset = $currentTarget.offset();
const offset = $currentTarget.offset();
$currentTarget.css({
position: "fixed",
top: offset.top,
@@ -788,15 +825,15 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
/**
* @private
* @param {CustomEvent} evt
*/
_onRestoreFlipCard: function(evt) {
var self = this;
this.$card.removeClass("active");
this.$front.removeClass("d-none");
if (this.$card.hasClass("oe_flip_card_maximized")) {
this.$card.removeClass("oe_flip_card_maximized");
this.$card.on("transitionend", function() {
self.$card.css({
this.$card.on("transitionend", () => {
this.$card.css({
position: "",
top: "",
left: "",
@@ -804,7 +841,7 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
height: "",
zIndex: "",
});
self.$card.off("transitionend");
this.$card.off("transitionend");
if (evt.data.success_callback) {
evt.data.success_callback();
}

View File

@@ -5,15 +5,15 @@ odoo.define(
function(require) {
"use strict";
var core = require("web.core");
var BasicRenderer = require("web.BasicRenderer");
var One2ManyProductPickerRecord = require("web_widget_one2many_product_picker.One2ManyProductPickerRecord");
var ProductPickerQuickCreateForm = require("web_widget_one2many_product_picker.ProductPickerQuickCreateForm");
const core = require("web.core");
const BasicRenderer = require("web.BasicRenderer");
const One2ManyProductPickerRecord = require("web_widget_one2many_product_picker.One2ManyProductPickerRecord");
const ProductPickerQuickCreateForm = require("web_widget_one2many_product_picker.ProductPickerQuickCreateForm");
var qweb = core.qweb;
const qweb = core.qweb;
/* This is the renderer of the main widget */
var One2ManyProductPickerRenderer = BasicRenderer.extend({
const One2ManyProductPickerRenderer = BasicRenderer.extend({
className: "oe_one2many_product_picker_view",
events: {
@@ -65,7 +65,7 @@ odoo.define(
* @param {Object} widget
*/
removeWidget: function(widget) {
var index = this.widgets.indexOf(widget);
const index = this.widgets.indexOf(widget);
widget.destroy();
delete this.widgets[index];
},
@@ -79,6 +79,8 @@ odoo.define(
/**
* @param {Object} search_data
* @param {Number} count
* @param {Object} search_group
*/
updateSearchData: function(search_data, count, search_group) {
this.search_data = search_data;
@@ -101,16 +103,15 @@ odoo.define(
* @override
*/
updateState: function(state, params) {
var self = this;
var force_update = params.force;
const force_update = params.force;
delete params.force;
var sparams = _.extend({}, params, {noRender: true});
const sparams = _.extend({}, params, {noRender: true});
if (!force_update && _.isEqual(this.state.data, state.data)) {
return this._super(state, sparams);
}
var old_state = _.clone(this.state.data);
return this._super(state, sparams).then(function() {
self._updateStateRecords(old_state);
const old_state = _.clone(this.state.data);
return this._super(state, sparams).then(() => {
this._updateStateRecords(old_state);
});
},
@@ -121,8 +122,8 @@ odoo.define(
* @param {Object} new_state
*/
updateRecord: function(state_id, new_state) {
for (var eb = this.widgets.length - 1; eb >= 0; --eb) {
var widget = this.widgets[eb];
for (let eb = this.widgets.length - 1; eb >= 0; --eb) {
const widget = this.widgets[eb];
if (widget.state.id === state_id) {
widget.recreate(new_state);
break;
@@ -130,46 +131,51 @@ odoo.define(
}
},
_isEqualState: function(state_a, state_b) {
if (state_a.id === state_b.id) {
return true;
}
const product_id_a =
state_a.data[this.options.field_map.product].data.id;
const product_id_b =
state_b.data[this.options.field_map.product].data.id;
return product_id_a === product_id_b;
},
/**
* When destroy states we need check if pure virtual records
* are affected to recreate a new one because this widget can't
* remove pure virtual records.
*
* @private
* @param {Array[Object]} states
* @returns {Deferred}
* @param {Array} states
* @returns {Array}
*/
_removeRecords: function(states, new_states) {
var defs = [];
var to_destroy = [];
for (var index_state in states) {
var state = states[index_state];
for (var e = this.widgets.length - 1; e >= 0; --e) {
var widget = this.widgets[e];
if (widget && widget.state.id === state.id) {
_processStatesToDestroy: function(states) {
const to_destroy = [];
for (const state of states) {
for (let e = this.widgets.length - 1; e >= 0; --e) {
const widget = this.widgets[e];
if (widget && this._isEqualState(widget.state, state)) {
to_destroy.push(widget);
delete this.widgets[e];
}
}
}
if (this.search_group.name === "main_lines") {
_.invoke(to_destroy, "destroy");
return $.when();
}
// If doesn't exists other records with the same product, we need
// create a 'pure virtual' record again.
for (var index_destroy in to_destroy) {
var widget_destroyed = to_destroy[index_destroy];
var widget_product_id =
widget_destroyed.state.data[this.options.field_map.product].data
.id;
var found = false;
const to_add = [];
for (const index_destroy in to_destroy) {
const widget_destroyed = to_destroy[index_destroy];
let found = false;
// If already exists a widget for the product don't try create a new one
for (var eb = this.widgets.length - 1; eb >= 0; --eb) {
var widget = this.widgets[eb];
for (let eb = this.widgets.length - 1; eb >= 0; --eb) {
const widget = this.widgets[eb];
if (
widget &&
widget.state &&
widget.state.data[this.options.field_map.product].data
.id === widget_product_id
this._isEqualState(widget.state, widget_destroyed.state)
) {
found = true;
break;
@@ -178,37 +184,110 @@ odoo.define(
if (!found) {
// Get the new state ID if exists to link it with the new record
var new_state_id = undefined;
for (var eb = new_states.length - 1; eb >= 0; --eb) {
var state = new_states[eb];
if (
state.data[this.options.field_map.product].data.id ===
widget_product_id
) {
new_state_id = state.id;
let state_id = null;
for (let eb = this.state.data.length - 1; eb >= 0; --eb) {
const state = this.state.data[eb];
if (this._isEqualState(state, widget_destroyed.state)) {
state_id = state.id;
break;
}
}
var search_record = _.find(this.search_data, {
id: widget_product_id,
});
var new_search_record = _.extend({}, search_record, {
__id: new_state_id,
});
var search_record_index = widget_destroyed.$el.index();
defs.push(
this.appendSearchRecords(
[new_search_record],
false,
true,
search_record_index
)[0]
);
// "Lines" section doesn't show virtual records
if (
(state_id && this.search_group.name === "main_lines") ||
this.search_group.name !== "main_lines"
) {
const widget_product_id =
widget_destroyed.state.data[
this.options.field_map.product
].data.id;
const search_record = _.find(this.search_data, {
id: widget_product_id,
});
const new_search_record = _.extend({}, search_record, {
__id: state_id,
});
const card_id = widget_destroyed.$el.data("cardId");
to_add.push([[new_search_record], false, true, card_id]);
}
}
}
_.invoke(to_destroy, "destroy");
return $.when(defs);
return [to_destroy, to_add];
},
/**
* We need check current states to ensure that doesn't exists duplications,
* update the existing and add the new ones.
*
* @private
* @returns {Array}
*/
_processCurrentStates: function() {
// Records to Update or Create
const to_destroy = [];
const to_add = [];
for (const index in this.state.data) {
const state = this.state.data[index];
let exists = false;
let search_record_index = -1;
let search_record = false;
for (let e = this.widgets.length - 1; e >= 0; --e) {
const widget = this.widgets[e];
if (!widget || !widget.state) {
// Already processed widget (deleted)
continue;
}
if (this._isEqualState(widget.state, state)) {
var model = this.getParent().getBasicFieldParams().model;
var record = model.get(widget.state.id);
model.updateRecordContext(state.id, {
lazy_qty: record.context.lazy_qty || 0,
});
widget.recreate(state);
exists = true;
break;
} else if (
widget.recordSearch.id ===
state.data[this.options.field_map.product].data.id
) {
// Is a new record (can be other record for the same 'search record' or a replacement for a pure virtual)
search_record_index = widget.$el.index();
search_record = widget.recordSearch;
var model = this.getParent().getBasicFieldParams().model;
var record = model.get(widget.state.id);
model.updateRecordContext(state.id, {
lazy_qty: record.context.lazy_qty || 0,
});
}
// Remove "pure virtual" records that have the same product that the new record
if (
widget.is_virtual &&
this._isEqualState(widget.state, state)
) {
to_destroy.push(widget);
delete this.widgets[e];
}
}
this.state.data = _.compact(this.state.data);
// Need add a new one?
if (!exists && search_record_index !== -1) {
const new_search_record = _.extend({}, search_record, {
__id: state.id,
});
to_add.push([
[new_search_record],
false,
true,
search_record_index,
]);
}
}
return [to_destroy, to_add];
},
/**
@@ -222,13 +301,13 @@ odoo.define(
*/
_updateStateRecords: function(old_states) {
// States to remove
var states_to_destroy = [];
for (var index in old_states) {
var old_state = old_states[index];
var found = false;
for (var e in this.state.data) {
var current_state = this.state.data[e];
if (current_state.id === old_state.id) {
const states_to_destroy = [];
for (const index in old_states) {
const old_state = old_states[index];
let found = false;
for (const e in this.state.data) {
const current_state = this.state.data[e];
if (this._isEqualState(current_state, old_state)) {
found = true;
break;
}
@@ -238,76 +317,53 @@ odoo.define(
}
}
const def = $.Deferred();
this.state.data = _.compact(this.state.data);
this._removeRecords(states_to_destroy, this.state.data);
const [to_destroy_old, to_add_virtual] = this._processStatesToDestroy(
states_to_destroy
);
// Records to Update or Create
var defs = [];
var to_destroy = [];
for (var index in this.state.data) {
var state = this.state.data[index];
var exists = false;
var search_record_index = -1;
var search_record = false;
for (var e = this.widgets.length - 1; e >= 0; --e) {
var widget = this.widgets[e];
if (!widget || !widget.state) {
// Already processed widget (deleted)
continue;
}
if (widget.state.id === state.id) {
widget.recreate(state);
exists = true;
break;
} else if (
widget.recordSearch.id ===
state.data[this.options.field_map.product].data.id
) {
// Is a new record
search_record_index = widget.$el.index();
search_record = widget.recordSearch;
}
// Remove "pure virtual" records that have the same product that the new record
if (
widget.is_virtual &&
widget.state.data[this.options.field_map.product].data
.id ===
state.data[this.options.field_map.product].data.id
) {
to_destroy.push(widget);
delete this.widgets[e];
}
}
this.state.data = _.compact(this.state.data);
// Need add a new one?
if (!exists && search_record_index !== -1) {
var new_search_record = _.extend({}, search_record, {
__id: state.id,
});
defs.push(
this.appendSearchRecords(
[new_search_record],
false,
true,
search_record_index
)[0]
);
}
// Make widgets to destroy invisible to avoid render 'dance'
for (const widget of to_destroy_old) {
widget.$el.hide();
}
_.invoke(to_destroy, "destroy");
return $.when(defs);
const oldTasks = [];
for (const params of to_add_virtual) {
oldTasks.push(this.appendSearchRecords.apply(this, params)[0]);
}
Promise.all(oldTasks).then(() => {
const [
to_destroy_current,
to_add_current,
] = this._processCurrentStates();
// Make widgets to destroy invisible to avoid render 'dance'
for (const widget of to_destroy_current) {
widget.$el.hide();
}
const currentTasks = [];
for (const params of to_add_current) {
currentTasks.push(
this.appendSearchRecords.apply(this, params)[0]
);
}
Promise.all(currentTasks).then(() => {
_.invoke(to_destroy_old, "destroy");
_.invoke(to_destroy_current, "destroy");
def.resolve();
});
});
return def;
},
/**
* @override
*/
_renderView: function() {
var self = this;
var oldWidgets = _.compact(this.widgets);
const oldWidgets = _.compact(this.widgets);
this.widgets = [];
this.$recordsContainer = $("<DIV/>", {
class: "w-100 row",
@@ -319,20 +375,20 @@ odoo.define(
"#productPickerLoadMore"
);
this.search_data = this._sort_search_data(this.search_data);
return $.Deferred(function(d) {
var defs = self.appendSearchRecords(self.search_data, true);
defs[0].then(function() {
return new Promise(resolve => {
const defs = this.appendSearchRecords(this.search_data, true);
Promise.all(defs).then(() => {
_.invoke(oldWidgets, "destroy");
self.$el.empty();
self.$el.append(self.$recordsContainer);
self.$el.append(self.$extraButtonsContainer);
self.showLoadMore(
self.last_search_data_count >= self.options.records_per_page
this.$el.empty();
this.$el.append(this.$recordsContainer);
this.$el.append(this.$extraButtonsContainer);
this.showLoadMore(
this.last_search_data_count >= this.options.records_per_page
);
if (self._isInDom) {
_.invoke(self.widgets, "on_attach_callback");
if (this._isInDom) {
_.invoke(this.widgets, "on_attach_callback");
}
d.resolve(defs[1]);
return resolve();
});
});
},
@@ -343,22 +399,20 @@ odoo.define(
*/
_sort_search_data: function(datas) {
if (this.search_group.name === "main_lines") {
var field_name = this.options.field_map.product;
for (var index_datas in datas) {
var data = datas[index_datas];
const field_name = this.options.field_map.product;
for (const index_datas in datas) {
const data = datas[index_datas];
for (var index_state in this.state.data) {
var state_data = this.state.data[index_state];
for (const index_state in this.state.data) {
const state_data = this.state.data[index_state];
if (state_data.data[field_name].res_id === data.id) {
data._order_value = state_data.res_id;
}
}
}
var sorted_datas = _.chain(datas)
const sorted_datas = _.chain(datas)
.sortBy("_order_value")
.map(function(item) {
return _.omit(item, "_order_value");
})
.map(item => _.omit(item, "_order_value"))
.value()
.reverse();
return sorted_datas;
@@ -371,19 +425,19 @@ odoo.define(
* Link a current state with the 'search record'.
*
* @private
* @param {Array[Object]} results
* @returns {Array[Object]}
* @param {Array} results
* @returns {Array}
*/
_processSearchRecords: function(results) {
var field_name = this.options.field_map.product;
var records = [];
for (var index in results) {
var record_search = results[index];
var state_data_found = false;
const field_name = this.options.field_map.product;
const records = [];
for (const index in results) {
const record_search = results[index];
let state_data_found = false;
for (var index_data in this.state.data) {
var state_record = this.state.data[index_data];
var field = state_record.data[field_name];
for (const index_data in this.state.data) {
const state_record = this.state.data[index_data];
const field = state_record.data[field_name];
if (
(typeof field === "object" &&
field.data.id === record_search.id) ||
@@ -411,8 +465,8 @@ odoo.define(
* @returns {Object}
*/
_getRecordDataById: function(id) {
for (var index in this.state.data) {
var record = this.state.data[index];
for (const index in this.state.data) {
const record = this.state.data[index];
if (record.id === id) {
return record;
}
@@ -444,7 +498,7 @@ odoo.define(
* Generates the 'Product Card' per record.
*
* @private
* @param {Array[Object]} search_records
* @param {Array} search_records
* @param {Boolean} no_process_records
* @param {Number} position
*/
@@ -453,46 +507,43 @@ odoo.define(
no_process_records,
position
) {
var self = this;
var processed_records = no_process_records
const processed_records = no_process_records
? search_records
: this._processSearchRecords(search_records);
_.each(processed_records, function(search_record) {
var state_data = self._getRecordDataById(search_record.__id);
var widget_options = self._getRecordOptions(search_record);
widget_options.renderer_widget_index = self.widgets.length;
var ProductPickerRecord = new One2ManyProductPickerRecord(
self,
_.each(processed_records, search_record => {
const state_data = this._getRecordDataById(search_record.__id);
const widget_options = this._getRecordOptions(search_record);
widget_options.renderer_widget_index = this.widgets.length;
const ProductPickerRecord = new One2ManyProductPickerRecord(
this,
state_data,
widget_options
);
self.widgets.push(ProductPickerRecord);
this.widgets.push(ProductPickerRecord);
// Simulate new lines to dispatch get_default & onchange's to get the
// relevant data to print. This case increase the TTI time.
if (!state_data) {
var defVirtualState = ProductPickerRecord.generateVirtualState();
if (defVirtualState.state() === "pending") {
self.defsVirtualState.push(defVirtualState);
}
const defVirtualState = ProductPickerRecord.generateVirtualState();
this.defsVirtualState.push(defVirtualState);
}
// At this point the widget will use the existing state (line) or
// the search data. Using search data instead of waiting for
// simulated state gives a low FCP time.
var def = ProductPickerRecord.appendTo(self.$recordsContainer).then(
const def = $.Deferred();
ProductPickerRecord.appendTo(this.$recordsContainer).then(
function(widget, widget_position) {
if (typeof widget_position !== "undefined") {
var $elm = this.$el.find(
"> div > div:nth(" + widget_position + ")"
const $elm = this.$el.find(
`[data-card-id="${position}"]`
);
widget.$el.insertAfter($elm);
widget.$el.insertBefore($elm);
}
}.bind(self, ProductPickerRecord, position)
def.resolve();
}.bind(this, ProductPickerRecord, position)
);
if (def.state() === "pending") {
self.defs.push(def);
}
this.defs.push(def);
});
},
@@ -506,11 +557,11 @@ odoo.define(
/**
* Append search records to the view
*
* @param {Array[Object]} search_records
* @param {Array} search_records
* @param {Boolean} no_attach_widgets
* @param {Boolean} no_process_records
* @param {Number} position
* @returns {Array[Deferred]}
* @returns {Array}
*/
appendSearchRecords: function(
search_records,
@@ -518,25 +569,24 @@ odoo.define(
no_process_records,
position
) {
var self = this;
this.trigger_up("loading_records");
this.defs = [];
this.defsVirtualState = [];
var cur_widget_index = this.widgets.length;
const cur_widget_index = this.widgets.length;
this._appendSearchRecords(search_records, no_process_records, position);
var defs = this.defs;
const defs = this.defs;
delete this.defs;
var defsVirtualState = this.defsVirtualState;
const defsVirtualState = this.defsVirtualState;
delete this.defsVirtualState;
return [
$.when.apply($, defs).then(function() {
if (!no_attach_widgets && self._isInDom) {
var new_widgets = self.widgets.slice(cur_widget_index);
Promise.all(defs).then(() => {
if (!no_attach_widgets && this._isInDom) {
const new_widgets = this.widgets.slice(cur_widget_index);
_.invoke(new_widgets, "on_attach_callback");
}
}),
$.when.apply($, defsVirtualState).then(function() {
self.trigger_up("loading_records", {finished: true});
Promise.all(defsVirtualState).then(() => {
this.trigger_up("loading_records", {finished: true});
}),
];
},
@@ -556,23 +606,22 @@ odoo.define(
* @param {Integer} index
*/
doWidgetFlip: function(index) {
var widget = this.widgets[index];
var $actived_card = this.$el.find(".active");
const widget = this.widgets[index];
const $actived_card = this.$el.find(".active");
if (widget.$card.hasClass("active")) {
widget.$card.removeClass("active");
widget.$card.find(".oe_flip_card_front").removeClass("d-none");
} else {
var self = widget;
widget.defs = [];
widget._processWidgetFields(widget.$back);
widget._processWidgets(widget.$back);
widget._processDynamicFields();
$.when(widget.defs).then(function() {
$.when(widget.defs).then(() => {
$actived_card.removeClass("active");
$actived_card.find(".oe_flip_card_front").removeClass("d-none");
self.$card.addClass("active");
setTimeout(function() {
self.$(".oe_flip_card_front").addClass("d-none");
widget.$card.addClass("active");
setTimeout(() => {
widget.$(".oe_flip_card_front").addClass("d-none");
}, 200);
});
}
@@ -585,11 +634,11 @@ odoo.define(
* @param {CustomEvent} evt
*/
_onRecordFlip: function(evt) {
var prev_widget_index = evt.data.prev_widget_index;
const prev_widget_index = evt.data.prev_widget_index;
if (typeof prev_widget_index !== "undefined") {
// Only check 'back' widgets so there is where the form was created
for (var index in this.widgets[prev_widget_index].widgets.back) {
var widget = this.widgets[prev_widget_index].widgets.back[
for (const index in this.widgets[prev_widget_index].widgets.back) {
const widget = this.widgets[prev_widget_index].widgets.back[
index
];
if (widget instanceof ProductPickerQuickCreateForm) {

View File

@@ -3,7 +3,7 @@
odoo.define("web_widget_one2many_product_picker.BasicModel", function(require) {
"use strict";
var BasicModel = require("web.BasicModel");
const BasicModel = require("web.BasicModel");
BasicModel.include({
/**
@@ -23,7 +23,7 @@ odoo.define("web_widget_one2many_product_picker.BasicModel", function(require) {
* @returns {Boolean}
*/
isPureVirtual: function(id) {
var data = this.localData[id];
const data = this.localData[id];
return data._virtual || false;
},
@@ -32,7 +32,7 @@ odoo.define("web_widget_one2many_product_picker.BasicModel", function(require) {
* @param {Boolean} status
*/
setPureVirtual: function(id, status) {
var data = this.localData[id];
const data = this.localData[id];
if (status) {
data._virtual = true;
} else {
@@ -44,9 +44,9 @@ odoo.define("web_widget_one2many_product_picker.BasicModel", function(require) {
* @param {Number/String} id
*/
unsetDirty: function(id) {
var data = this.localData[id];
const data = this.localData[id];
data._isDirty = false;
this._visitChildren(data, function(r) {
this._visitChildren(data, r => {
r._isDirty = false;
});
},
@@ -59,12 +59,11 @@ odoo.define("web_widget_one2many_product_picker.BasicModel", function(require) {
* @returns {Deferred}
*/
createVirtualRecord: function(listID, options) {
var self = this;
var list = this.localData[listID];
var context = _.extend({}, this._getContext(list), options.context);
const list = this.localData[listID];
const context = _.extend({}, this._getContext(list), options.context);
var position = options ? options.position : "top";
var params = {
const position = options ? options.position : "top";
const params = {
context: context,
fields: list.fields,
fieldsInfo: list.fieldsInfo,
@@ -75,18 +74,16 @@ odoo.define("web_widget_one2many_product_picker.BasicModel", function(require) {
doNotSetDirty: true,
};
return $.Deferred(function(d) {
self._makeDefaultRecord(list.model, params).then(function(recordID) {
self.setPureVirtual(recordID, true);
self.updateRecordContext(recordID, {ignore_warning: true});
return new Promise(resolve => {
this._makeDefaultRecord(list.model, params).then(recordID => {
this.setPureVirtual(recordID, true);
this.updateRecordContext(recordID, {ignore_warning: true});
if (options.data) {
self._applyChange(recordID, options.data, params).then(
function() {
d.resolve(self.get(recordID));
}
);
this._applyChange(recordID, options.data, params).then(() => {
resolve(this.get(recordID));
});
} else {
d.resolve(self.get(recordID));
resolve(this.get(recordID));
}
});
});
@@ -100,13 +97,14 @@ odoo.define("web_widget_one2many_product_picker.BasicModel", function(require) {
*
* @override
*/
_performOnChange: function(record, fields, viewType) {
_performOnChange: function(record) {
if (record.context && record.context.ignore_warning) {
var this_mp = _.clone(this);
var super_call = this.trigger_up;
const this_mp = _.clone(this);
const super_call = this.trigger_up;
this_mp.trigger_up = function(event_name, data) {
if (event_name === "warning" && data.type === "dialog") {
return; // Do nothing
// Do nothing
return;
}
return super_call.apply(this, arguments);
}.bind(this);

View File

@@ -4,15 +4,15 @@
odoo.define("web_widget_one2many_product_picker.BasicView", function(require) {
"use strict";
var core = require("web.core");
var pyUtils = require("web.py_utils");
var BasicView = require("web.BasicView");
const core = require("web.core");
const pyUtils = require("web.py_utils");
const BasicView = require("web.BasicView");
var _t = core._t;
const _t = core._t;
// Add ref to _() -> _t() call
var PY_t = new py.PY_def.fromJSON(function() {
var args = py.PY_parseArgs(arguments, ["str"]);
const PY_t = new py.PY_def.fromJSON(function() {
const args = py.PY_parseArgs(arguments, ["str"]);
return py.str.fromJSON(_t(args.str.toJSON()));
});

View File

@@ -5,17 +5,17 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
) {
"use strict";
var core = require("web.core");
var field_registry = require("web.field_registry");
var FieldOne2Many = require("web.relational_fields").FieldOne2Many;
var One2ManyProductPickerRenderer = require("web_widget_one2many_product_picker.One2ManyProductPickerRenderer");
var tools = require("web_widget_one2many_product_picker.tools");
const core = require("web.core");
const field_registry = require("web.field_registry");
const FieldOne2Many = require("web.relational_fields").FieldOne2Many;
const One2ManyProductPickerRenderer = require("web_widget_one2many_product_picker.One2ManyProductPickerRenderer");
const tools = require("web_widget_one2many_product_picker.tools");
var _t = core._t;
var qweb = core.qweb;
const _t = core._t;
const qweb = core.qweb;
/* This is the main widget */
var FieldOne2ManyProductPicker = FieldOne2Many.extend({
const FieldOne2ManyProductPicker = FieldOne2Many.extend({
className: "oe_field_one2many_product_picker",
// Workaround: We need know all records,
@@ -24,10 +24,9 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
events: _.extend({}, FieldOne2Many.prototype.events, {
"click .dropdown-item": "_onClickSearchMode",
"click .oe_search_erase": "_onClickSearchEraser",
"click .oe_btn_lines": "_onClickLines",
"click .oe_btn_search_group": "_onClickSearchGroup",
"keypress .oe_search_input": "_onKeyPressSearch",
"search .oe_search_input": "_onSearch",
"show.bs.dropdown .o_cp_buttons": "_onShowSearchDropdown",
}),
custom_events: _.extend({}, FieldOne2Many.prototype.custom_events, {
@@ -82,7 +81,7 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
*/
willStart: function() {
if (!this.view) {
return $.when();
return Promise.resolve();
}
// Uses to work with searchs, so we can mix properties with the user values.
@@ -98,14 +97,17 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
};
this._searchContext.activeTest = false;
}
return $.when(this._super.apply(this, arguments), this._getSearchRecords());
return Promise.all([
this._super.apply(this, arguments),
this._getSearchRecords(),
]);
},
/**
* Updates the lines counter badge
*/
updateBadgeLines: function() {
var records = this.parent_controller.model.get(this.state.id).data[
const records = this.parent_controller.model.get(this.state.id).data[
this.name
].data;
this.$badgeLines.text(records.length);
@@ -115,13 +117,13 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
if (!this.options.show_subtotal) {
return;
}
var prices = [];
var field_map = this.options.field_map;
var records = this.parent_controller.model.get(this.state.id).data[
let prices = [];
const field_map = this.options.field_map;
const records = this.parent_controller.model.get(this.state.id).data[
this.name
].data;
if (this.options.show_discount) {
prices = _.map(records, function(line) {
prices = _.map(records, line => {
return (
line.data[field_map.product_uom_qty] *
tools.priceReduce(
@@ -131,15 +133,15 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
);
});
} else {
prices = _.map(records, function(line) {
prices = _.map(records, line => {
return (
line.data[field_map.product_uom_qty] *
line.data[field_map.price_unit]
);
});
}
var total =
_.reduce(prices, function(a, b) {
let total =
_.reduce(prices, (a, b) => {
return a + b;
}) || 0;
total = tools.monetary(
@@ -185,10 +187,10 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
*/
_processGroups: function() {
this.searchGroups = [];
var hasUserActive = false;
var groups = this.options.groups || [];
for (var groupIndex in groups) {
var group_def = groups[groupIndex];
let hasUserActive = false;
const groups = this.options.groups || [];
for (const groupIndex in groups) {
const group_def = groups[groupIndex];
if (group_def.active) {
group_def.active = !hasUserActive;
hasUserActive = true;
@@ -213,11 +215,10 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
* @override
*/
_renderControlPanel: function() {
var self = this;
return this._super.apply(this, arguments).then(function() {
self.control_panel.update({
return this._super.apply(this, arguments).then(() => {
this._controlPanel.updateContents({
cp_content: {
$buttons: self.$buttons,
$buttons: this.$buttons,
$pager: false,
},
});
@@ -253,21 +254,20 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
* @override
*/
_render: function() {
var self = this;
var def = this._super.apply(this, arguments);
const def = this._super.apply(this, arguments);
// Parent implementation can return 'undefined' :(
return (
def &&
def.then(function() {
def.then(() => {
if (
!self.$el.hasClass("oe_field_one2many_product_picker_maximized")
!this.$el.hasClass("oe_field_one2many_product_picker_maximized")
) {
self.$el.addClass("position-relative d-flex flex-column");
this.$el.addClass("position-relative d-flex flex-column");
}
self._addMaximizeButton();
if (self.options.show_subtotal) {
self._addTotalsZone();
this._addMaximizeButton();
if (this.options.show_subtotal) {
this._addTotalsZone();
}
})
);
@@ -277,15 +277,10 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
* @returns {Deferred}
*/
doRenderSearchRecords: function() {
var self = this;
return $.Deferred(function(d) {
self._getSearchRecords().then(function() {
self.renderer.$el.scrollTop(0);
self.renderer._renderView().then(function(virtualStateDefs) {
virtualStateDefs.then(function() {
d.resolve();
});
});
return new Promise(resolve => {
this._getSearchRecords().then(() => {
this.renderer.$el.scrollTop(0);
this.renderer._renderView().then(() => resolve());
});
});
},
@@ -325,17 +320,16 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
* @returns {Deferred}
*/
_getSearchRecords: function(options, merge) {
var self = this;
var arch = this.view.arch;
var field_name = this.options.field_map.product;
var field_info = this.view.fieldsInfo[arch.tag][field_name];
var model = this.view.viewFields[field_info.name].relation;
const arch = this.view.arch;
const field_name = this.options.field_map.product;
const field_info = this.view.fieldsInfo[arch.tag][field_name];
const model = this.view.viewFields[field_info.name].relation;
// Launch the rpc request and ensures that we wait for the reply
// to continue
var domain = this._getFullSearchDomain();
var soptions = options || {};
var context = _.extend(
const domain = this._getFullSearchDomain();
const soptions = options || {};
const context = _.extend(
{
active_search_group_name: this._activeSearchGroup.name,
active_search_involved_fields: this._searchContext.involvedFields,
@@ -344,37 +338,37 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
this.value.getContext()
);
return $.Deferred(function(d) {
var limit = soptions.limit || self.options.records_per_page;
var offset = soptions.offset || 0;
self._rpc({
return new Promise(resolve => {
const limit = soptions.limit || this.options.records_per_page;
const offset = soptions.offset || 0;
this._rpc({
model: model,
method: "search_read",
fields: self.search_read_fields,
fields: this.search_read_fields,
domain: domain,
limit: limit,
offset: offset,
orderBy: self._searchContext.order,
orderBy: this._searchContext.order,
kwargs: {context: context},
}).then(function(results) {
}).then(results => {
if (merge) {
self._searchRecords = _.union(
self._searchRecords || [],
this._searchRecords = _.union(
this._searchRecords || [],
results
);
} else {
self._searchRecords = results;
this._searchRecords = results;
}
self._lastSearchRecordsCount = results.length;
self._searchOffset = offset + limit;
if (self.renderer) {
self.renderer.updateSearchData(
self._searchRecords,
self._lastSearchRecordsCount,
self._activeSearchGroup
this._lastSearchRecordsCount = results.length;
this._searchOffset = offset + limit;
if (this.renderer) {
this.renderer.updateSearchData(
this._searchRecords,
this._lastSearchRecordsCount,
this._activeSearchGroup
);
}
d.resolve(results);
resolve(results);
});
});
},
@@ -384,8 +378,8 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
* @param {MouseEvent} evt
*/
_onClickSearchGroup: function(evt) {
var $btn = $(evt.target);
var groupIndex = Number($btn.data("group")) || 0;
const $btn = $(evt.target);
const groupIndex = Number($btn.data("group")) || 0;
this._activeSearchGroup = this.searchGroups[groupIndex];
this._searchContext.domain = this._activeSearchGroup.domain;
this._searchContext.order = this._activeSearchGroup.order;
@@ -422,17 +416,16 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
* @param {MouseEvent} ev
*/
_onClickSearchMode: function(ev) {
var self = this;
ev.preventDefault();
var $target = $(ev.target);
const $target = $(ev.target);
this._searchMode = $target.index();
$target
.parent()
.children()
.removeClass("active");
$target.addClass("active");
this.doRenderSearchRecords().then(function() {
self.$searchInput.focus();
this.doRenderSearchRecords().then(() => {
this.$searchInput.focus();
});
},
@@ -470,17 +463,17 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
*/
_getFullSearchDomain: function() {
this._searchContext.involvedFields = [];
var domain = _.clone(this._searchContext.domain) || [];
const domain = _.clone(this._searchContext.domain) || [];
if (this._searchContext.text) {
var search_domain = this.options.search;
let search_domain = this.options.search;
if (!(search_domain[0] instanceof Array)) {
search_domain = search_domain[this._searchMode].domain;
}
var involved_fields = [];
const involved_fields = [];
// Iterate domain triplets and logic operators
for (var index in search_domain) {
var domain_cloned = _.clone(search_domain[index]);
for (const index in search_domain) {
const domain_cloned = _.clone(search_domain[index]);
// Is a triplet
if (domain_cloned instanceof Array) {
@@ -525,10 +518,11 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
if (!this.view) {
return [];
}
var field_name = this.options.field_map.product;
var lines = this.parent_controller.model.get(this.state.id).data[this.name]
.data;
var ids = _.map(lines, function(line) {
const field_name = this.options.field_map.product;
const lines = this.parent_controller.model.get(this.state.id).data[
this.name
].data;
const ids = _.map(lines, line => {
return line.data[field_name].data.id;
});
return [["id", "in", ids]];
@@ -562,24 +556,23 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
this._searchContext.text = "";
},
_onKeyPressSearch: function(evt) {
/**
* Odoo stop bubble of the event, but we need listen it.
*
* @override
*/
_onKeydown: function(evt) {
if (evt.keyCode === $.ui.keyCode.ENTER) {
var self = this;
this._searchContext.text = evt.target.value;
this.doRenderSearchRecords().then(function() {
self.$searchInput.focus();
});
// Do nothing
return;
}
return this._super.apply(this, arguments);
},
/**
* @private
*/
_onClickSearchEraser: function() {
var self = this;
this._clearSearchInput();
this.doRenderSearchRecords().then(function() {
self.$searchInput.focus();
_onSearch: function(evt) {
this._searchContext.text = evt.target.value;
this.doRenderSearchRecords().then(() => {
this.$searchInput.focus();
});
},
@@ -589,11 +582,11 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
*/
_onShowSearchDropdown: function(evt) {
// Workaround: This "ensures" a correct dropdown position
var offset = $(evt.currentTarget)
const offset = $(evt.currentTarget)
.find(".dropdown-toggle")
.parent()
.height();
_.defer(function() {
_.defer(() => {
$(evt.currentTarget)
.find(".dropdown-menu")
.css("transform", "translate3d(0px, " + offset + "px, 0px)");
@@ -608,7 +601,6 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
*/
_onCreateQuickRecord: function(evt) {
evt.stopPropagation();
var self = this;
this.parent_controller.model.setPureVirtual(evt.data.id, false);
if (this.options.auto_save) {
@@ -616,23 +608,22 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
this._setValue(
{operation: "ADD", id: evt.data.id},
{notifyChange: false}
).then(function() {
if (self.options.auto_save) {
self.parent_controller
.saveRecord(undefined, {stayInEdit: true})
.then(function(rrr) {
// Because 'create' generates a new state and we can't know these new id we
// need force update the all the current states.
self._setValue(
{operation: "UPDATE", id: evt.data.id},
{doNotSetDirty: true}
).then(function() {
if (evt.data.callback) {
evt.data.callback();
}
});
).then(() => {
this.parent_controller
.saveRecord(undefined, {stayInEdit: true})
.then(() => {
// Because 'create' generates a new state and we can't know these new id we
// need force update all the current states.
this._setValue(
{operation: "UPDATE", id: evt.data.id},
{doNotSetDirty: true}
).then(() => {
if (evt.data.callback) {
evt.data.callback();
}
});
} else if (evt.data.callback) {
});
if (evt.data.callback) {
evt.data.callback();
}
});
@@ -642,7 +633,7 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
product_picker_modified: true,
});
// This will trigger an "state" update
this._setValue({operation: "ADD", id: evt.data.id}).then(function() {
this._setValue({operation: "ADD", id: evt.data.id}).then(() => {
if (evt.data.callback) {
evt.data.callback();
}
@@ -650,6 +641,53 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
}
},
_doUpdateQuickRecord: function(id, data, callback) {
if (this.options.auto_save) {
var self = this;
// Dont trigger state update
this._setValue(
{operation: "UPDATE", id: id, data: data},
{notifyChange: false}
).then(function() {
self.parent_controller
.saveRecord(undefined, {stayInEdit: true})
.then(function() {
// Workaround to get updated values
self.parent_controller.model
.reload(self.value.id)
.then(function(result) {
var new_data = self.parent_controller.model.get(
result
);
self.value.data = new_data.data;
self.renderer.updateState(self.value, {
force: true,
});
if (callback) {
callback();
}
});
});
if (callback) {
callback();
}
});
} else {
// This is used to know when need use 'yellow' color
this.parent_controller.model.updateRecordContext(id, {
product_picker_modified: true,
});
// This will trigger an "state" update
this._setValue({operation: "UPDATE", id: id, data: data}).then(
function() {
if (callback) {
callback();
}
}
);
}
},
/**
* Runs the x2many (1,id,values) command.
*
@@ -658,67 +696,21 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
*/
_onUpdateQuickRecord: function(evt) {
evt.stopPropagation();
var self = this;
if (this.options.auto_save) {
// Dont trigger state update
this._setValue(
{operation: "UPDATE", id: evt.data.id, data: evt.data.data},
{notifyChange: false}
).then(function() {
if (self.options.auto_save) {
self.parent_controller
.saveRecord(undefined, {stayInEdit: true})
.then(function() {
// Workaround to get updated values
self.parent_controller.model
.reload(self.value.id)
.then(function(result) {
var new_data = self.parent_controller.model.get(
result
);
self.value.data = new_data.data;
self.renderer.updateState(self.value, {
force: true,
});
if (evt.data.callback) {
evt.data.callback();
}
});
});
} else if (evt.data.callback) {
evt.data.callback();
}
});
} else {
// This is used to know when need use 'yellow' color
this.parent_controller.model.updateRecordContext(evt.data.id, {
product_picker_modified: true,
});
// This will trigger an "state" update
this._setValue({
operation: "UPDATE",
id: evt.data.id,
data: evt.data.data,
}).then(function() {
if (evt.data.callback) {
evt.data.callback();
}
});
}
this._doUpdateQuickRecord(evt.data.id, evt.data.data, evt.data.callback);
},
/**
* Handle auto_save when remove a record
*
* @param {CustomEvent} evt
*/
_onListRecordRemove: function(evt) {
evt.stopPropagation();
var self = this;
this._setValue({operation: "DELETE", ids: [evt.data.id]}).then(function() {
if (self.options.auto_save) {
self.parent_controller
this._setValue({operation: "DELETE", ids: [evt.data.id]}).then(() => {
if (this.options.auto_save) {
this.parent_controller
.saveRecord(undefined, {stayInEdit: true})
.then(function() {
.then(() => {
if (evt.data.callback) {
evt.data.callback();
}
@@ -746,14 +738,13 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
if (this._isLoading) {
return;
}
var self = this;
this._getSearchRecords(
{
offset: this._searchOffset,
},
true
).then(function(records) {
self.renderer.appendSearchRecords(records);
).then(records => {
this.renderer.appendSearchRecords(records);
});
},
@@ -784,12 +775,10 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
*
* @override
*/
_setValue: function(value, options) {
var self = this;
return this._super.apply(this, arguments).then(function() {
self.updateBadgeLines();
self.updateSubtotalPrice();
_setValue: function() {
return this._super.apply(this, arguments).then(() => {
this.updateBadgeLines();
this.updateSubtotalPrice();
});
},
});

View File

@@ -67,10 +67,6 @@
height $one2many-product-picker-transition-3d-time;
height: $one2many-product-picker-card-min-height;
&.blocked {
filter: blur(2px);
}
&.disabled {
filter: grayscale(100%);
opacity: 0.5;
@@ -235,36 +231,3 @@
}
}
}
.oe_product_picker_quick_modif_price {
width: 80%;
max-width: $one2many-product-picker-quick-modif-price-max-width;
margin: auto;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
border: 1px solid $border-color;
z-index: 55;
.oe_one2many_product_picker_form_buttons {
text-align: center;
}
}
.oe_product_picker_catch_attention {
position: relative;
animation: productPickerCatchAttention 200ms normal forwards;
}
@keyframes productPickerCatchAttention {
0% {
transform: scale(1);
}
50% {
transform: scale(1.5);
}
100% {
transform: scale(1);
}
}

View File

@@ -39,14 +39,6 @@
aria-label="Search..."
aria-describedby="btnGroupAddon2"
/>
<div class="input-group-append">
<button
type="button"
t-attf-class="btn btn-secondary btn-lg input-group-button oe_search_erase"
>
<i class="fa fa-eraser" />
</button>
</div>
</div>
</div>
</t>
@@ -97,16 +89,31 @@
<t t-name="One2ManyProductPicker.FlipCard">
<div
class="oe_flip_container p-1 col-12 col-sm-8 col-md-6 col-lg-4 col-xl-3 col-xxl-2"
t-att-data-card-id="state &amp;&amp; state.id || record_search.id"
>
<div
t-attf-class="oe_flip_card {{!state &amp;&amp; 'disabled' || (auto_save &amp;&amp; !is_virtual &amp;&amp; !state.data.id &amp;&amp; 'blocked') || ''}}"
t-attf-class="oe_flip_card {{!state &amp;&amp; 'disabled' || (auto_save &amp;&amp; (!is_virtual || is_saving) &amp;&amp; !state.data.id &amp;&amp; 'blocked') || ''}}"
>
<div class="oe_flip_card_inner text-center">
<div
t-attf-class="oe_flip_card_front p-0 {{(modified &amp;&amp; 'border-warning') || (state &amp;&amp; !is_virtual &amp;&amp; 'border-success') || ''}}"
t-attf-class="oe_flip_card_front p-0 {{((modified || is_saving) &amp;&amp; 'border-warning') || (state &amp;&amp; !is_virtual &amp;&amp; 'border-success') || ''}}"
>
<t t-if="state">
<t t-if="!is_virtual">
<t t-if="is_saving || lazy_qty > 0">
<div
class="safezone position-absolute m-0 pb-2 pr-2 text-left"
>
<span
class="badge record_saving badge-warning font-weight-bold rounded-0 mt-0 px-2 py-3 product_qty"
><span
class="lazy_product_qty"
t-esc="lazy_qty || '1'"
/> x <t
t-esc="state.data[field_map.product_uom].data.display_name"
/></span>
</div>
</t>
<t t-elif="!is_virtual">
<div
class="safezone position-absolute m-0 pb-2 pr-2 text-left"
>
@@ -187,7 +194,34 @@
</div>
</div>
</t>
<t t-name="One2ManyProductPicker.QuickModifPricePopup">
<div class="oe_product_picker_quick_modif_price shadow" />
<t t-name="One2ManyProductPicker.QuickModifPrice.Modal">
<div
class="oe_product_picker_quick_modif_price modal fade"
id="One2ManyProductPickerQuickModifPrice"
tabindex="-1"
role="dialog"
aria-labelledby="One2ManyProductPickerQuickModifPriceLabel"
aria-hidden="true"
>
<div class="modal-dialog modal-sm modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-body p-0" />
<div class="modal-footer">
<button
class="btn btn-success oe_record_change mr-auto"
data-dismiss="modal"
>
<i class="fa fa-check" />
</button>
<button
class="btn btn-warning oe_record_discard"
data-dismiss="modal"
>
<i class="fa fa-times" />
</button>
</div>
</div>
</div>
</div>
</t>
</template>

View File

@@ -1,17 +1,7 @@
<template>
<t t-name="One2ManyProductPicker.QuickModifPrice.FormButtons">
<div class="oe_one2many_product_picker_form_buttons">
<button class="btn btn-success oe_record_change mr-2">
<i class="fa fa-check" />
</button>
<button class="btn btn-warning oe_record_discard ml-2">
<i class="fa fa-times" />
</button>
</div>
</t>
<t t-name="One2ManyProductPicker.QuickModifPrice.Price">
<div class="text-left">
<strong>Price:</strong>
<strong>Price</strong>
<div class="oe_price" />
</div>
</t>