mirror of https://github.com/OCA/web.git
[IMP] web_widget_one2many_product_picker: Better usability
parent
c8f718cc3a
commit
aa4ef9b0ed
|
@ -180,6 +180,11 @@ Other example for 'purchase.order.line' fields:
|
||||||
Usage
|
Usage
|
||||||
=====
|
=====
|
||||||
|
|
||||||
|
Parts of the widget:
|
||||||
|
~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. image:: https://raw.githubusercontent.com/OCA/web/12.0/web_widget_one2many_product_picker/static/img/product_picker_anat.png
|
||||||
|
|
||||||
Preview:
|
Preview:
|
||||||
~~~~~~~~
|
~~~~~~~~
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
|
Parts of the widget:
|
||||||
|
~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. image:: ../static/img/product_picker_anat.png
|
||||||
|
|
||||||
Preview:
|
Preview:
|
||||||
~~~~~~~~
|
~~~~~~~~
|
||||||
|
|
||||||
|
|
|
@ -380,15 +380,16 @@ ul.auto-toc {
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li><a class="reference internal" href="#usage" id="id6">Usage</a><ul>
|
<li><a class="reference internal" href="#usage" id="id6">Usage</a><ul>
|
||||||
<li><a class="reference internal" href="#preview" id="id7">Preview:</a></li>
|
<li><a class="reference internal" href="#parts-of-the-widget" id="id7">Parts of the widget:</a></li>
|
||||||
|
<li><a class="reference internal" href="#preview" id="id8">Preview:</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li><a class="reference internal" href="#known-issues-roadmap" id="id8">Known issues / Roadmap</a></li>
|
<li><a class="reference internal" href="#known-issues-roadmap" id="id9">Known issues / Roadmap</a></li>
|
||||||
<li><a class="reference internal" href="#bug-tracker" id="id9">Bug Tracker</a></li>
|
<li><a class="reference internal" href="#bug-tracker" id="id10">Bug Tracker</a></li>
|
||||||
<li><a class="reference internal" href="#credits" id="id10">Credits</a><ul>
|
<li><a class="reference internal" href="#credits" id="id11">Credits</a><ul>
|
||||||
<li><a class="reference internal" href="#authors" id="id11">Authors</a></li>
|
<li><a class="reference internal" href="#authors" id="id12">Authors</a></li>
|
||||||
<li><a class="reference internal" href="#contributors" id="id12">Contributors</a></li>
|
<li><a class="reference internal" href="#contributors" id="id13">Contributors</a></li>
|
||||||
<li><a class="reference internal" href="#maintainers" id="id13">Maintainers</a></li>
|
<li><a class="reference internal" href="#maintainers" id="id14">Maintainers</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -564,22 +565,28 @@ options="{'search': [{'name': _('Starts With'), 'domain': [('name', '=like'
|
||||||
</div>
|
</div>
|
||||||
<div class="section" id="usage">
|
<div class="section" id="usage">
|
||||||
<h1><a class="toc-backref" href="#id6">Usage</a></h1>
|
<h1><a class="toc-backref" href="#id6">Usage</a></h1>
|
||||||
|
<div class="section" id="parts-of-the-widget">
|
||||||
|
<h2><a class="toc-backref" href="#id7">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" />
|
||||||
|
</blockquote>
|
||||||
|
</div>
|
||||||
<div class="section" id="preview">
|
<div class="section" id="preview">
|
||||||
<h2><a class="toc-backref" href="#id7">Preview:</a></h2>
|
<h2><a class="toc-backref" href="#id8">Preview:</a></h2>
|
||||||
<blockquote>
|
<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/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" />
|
||||||
</blockquote>
|
</blockquote>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="section" id="known-issues-roadmap">
|
<div class="section" id="known-issues-roadmap">
|
||||||
<h1><a class="toc-backref" href="#id8">Known issues / Roadmap</a></h1>
|
<h1><a class="toc-backref" href="#id9">Known issues / Roadmap</a></h1>
|
||||||
<ul class="simple">
|
<ul class="simple">
|
||||||
<li>Translations in the xml ‘options’ attribute of the field that use the widget can’t be exported automatically to be translated</li>
|
<li>Translations in the xml ‘options’ attribute of the field that use the widget can’t be exported automatically to be translated</li>
|
||||||
<li>The product card animations can be improved. Currently the card is recreated, so we lost some elements to apply correct effects.</li>
|
<li>The product card animations can be improved. Currently the card is recreated, so we lost some elements to apply correct effects.</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="section" id="bug-tracker">
|
<div class="section" id="bug-tracker">
|
||||||
<h1><a class="toc-backref" href="#id9">Bug Tracker</a></h1>
|
<h1><a class="toc-backref" href="#id10">Bug Tracker</a></h1>
|
||||||
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/web/issues">GitHub Issues</a>.
|
<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.
|
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
|
If you spotted it first, help us smashing it by providing a detailed and welcomed
|
||||||
|
@ -587,15 +594,15 @@ If you spotted it first, help us smashing it by providing a detailed and welcome
|
||||||
<p>Do not contact contributors directly about support or help with technical issues.</p>
|
<p>Do not contact contributors directly about support or help with technical issues.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="section" id="credits">
|
<div class="section" id="credits">
|
||||||
<h1><a class="toc-backref" href="#id10">Credits</a></h1>
|
<h1><a class="toc-backref" href="#id11">Credits</a></h1>
|
||||||
<div class="section" id="authors">
|
<div class="section" id="authors">
|
||||||
<h2><a class="toc-backref" href="#id11">Authors</a></h2>
|
<h2><a class="toc-backref" href="#id12">Authors</a></h2>
|
||||||
<ul class="simple">
|
<ul class="simple">
|
||||||
<li>Tecnativa</li>
|
<li>Tecnativa</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="section" id="contributors">
|
<div class="section" id="contributors">
|
||||||
<h2><a class="toc-backref" href="#id12">Contributors</a></h2>
|
<h2><a class="toc-backref" href="#id13">Contributors</a></h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li><p class="first"><a class="reference external" href="https://www.tecnativa.com">Tecnativa</a>:</p>
|
<li><p class="first"><a class="reference external" href="https://www.tecnativa.com">Tecnativa</a>:</p>
|
||||||
<blockquote>
|
<blockquote>
|
||||||
|
@ -609,7 +616,7 @@ If you spotted it first, help us smashing it by providing a detailed and welcome
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="section" id="maintainers">
|
<div class="section" id="maintainers">
|
||||||
<h2><a class="toc-backref" href="#id13">Maintainers</a></h2>
|
<h2><a class="toc-backref" href="#id14">Maintainers</a></h2>
|
||||||
<p>This module is maintained by the OCA.</p>
|
<p>This module is maintained by the OCA.</p>
|
||||||
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a>
|
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a>
|
||||||
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose
|
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 124 KiB |
|
@ -89,9 +89,9 @@ odoo.define("web_widget_one2many_product_picker.ProductPickerQuickCreateForm", f
|
||||||
model: this.basicFieldParams.model,
|
model: this.basicFieldParams.model,
|
||||||
mainRecordData: this.getParent().getParent().state,
|
mainRecordData: this.getParent().getParent().state,
|
||||||
});
|
});
|
||||||
if (this.id) {
|
// if (this.id) {
|
||||||
this.basicFieldParams.model.save(this.id, {savePoint: true});
|
// this.basicFieldParams.model.save(this.id, {savePoint: true});
|
||||||
}
|
// }
|
||||||
var def2 = this.formView.getController(this).then(function (controller) {
|
var def2 = this.formView.getController(this).then(function (controller) {
|
||||||
self.controller = controller;
|
self.controller = controller;
|
||||||
self.$el.empty();
|
self.$el.empty();
|
||||||
|
|
|
@ -126,6 +126,10 @@ odoo.define("web_widget_one2many_product_picker.ProductPickerQuickCreateFormView
|
||||||
state: this._getRecordState(),
|
state: this._getRecordState(),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (this._disabled) {
|
||||||
|
this._disableQuickCreate();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -138,7 +142,7 @@ odoo.define("web_widget_one2many_product_picker.ProductPickerQuickCreateFormView
|
||||||
// Ensures that the record won't be created twice
|
// Ensures that the record won't be created twice
|
||||||
this._disabled = true;
|
this._disabled = true;
|
||||||
this.$el.addClass("o_disabled");
|
this.$el.addClass("o_disabled");
|
||||||
this.$("input:not(:disabled)")
|
this.$("input:not(:disabled),button:not(:disabled)")
|
||||||
.addClass("o_temporarily_disabled")
|
.addClass("o_temporarily_disabled")
|
||||||
.attr("disabled", "disabled");
|
.attr("disabled", "disabled");
|
||||||
},
|
},
|
||||||
|
@ -151,7 +155,7 @@ odoo.define("web_widget_one2many_product_picker.ProductPickerQuickCreateFormView
|
||||||
// Allows to create again
|
// Allows to create again
|
||||||
this._disabled = false;
|
this._disabled = false;
|
||||||
this.$el.removeClass("o_disabled");
|
this.$el.removeClass("o_disabled");
|
||||||
this.$("input.o_temporarily_disabled")
|
this.$("input.o_temporarily_disabled,button.o_temporarily_disabled")
|
||||||
.removeClass("o_temporarily_disabled")
|
.removeClass("o_temporarily_disabled")
|
||||||
.attr("disabled", false);
|
.attr("disabled", false);
|
||||||
},
|
},
|
||||||
|
@ -234,15 +238,14 @@ odoo.define("web_widget_one2many_product_picker.ProductPickerQuickCreateFormView
|
||||||
* @returns {Deferred}
|
* @returns {Deferred}
|
||||||
*/
|
*/
|
||||||
_add: function () {
|
_add: function () {
|
||||||
this.model.updateRecordContext(this.handle, {
|
|
||||||
has_changes_confirmed: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (this._disabled) {
|
if (this._disabled) {
|
||||||
|
|
||||||
// Don't do anything if we are already creating a record
|
// Don't do anything if we are already creating a record
|
||||||
return $.Deferred();
|
return $.Deferred();
|
||||||
}
|
}
|
||||||
|
this.model.updateRecordContext(this.handle, {
|
||||||
|
has_changes_confirmed: true,
|
||||||
|
});
|
||||||
var self = this;
|
var self = this;
|
||||||
this._disableQuickCreate();
|
this._disableQuickCreate();
|
||||||
return this.saveRecord(this.handle, {
|
return this.saveRecord(this.handle, {
|
||||||
|
@ -251,39 +254,70 @@ odoo.define("web_widget_one2many_product_picker.ProductPickerQuickCreateFormView
|
||||||
savePoint: true,
|
savePoint: true,
|
||||||
viewType: "form",
|
viewType: "form",
|
||||||
}).then(function () {
|
}).then(function () {
|
||||||
self._enableQuickCreate();
|
|
||||||
var record = self.model.get(self.handle);
|
var record = self.model.get(self.handle);
|
||||||
|
self.trigger_up("restore_flip_card", {
|
||||||
|
success_callback: function () {
|
||||||
self.trigger_up("create_quick_record", {
|
self.trigger_up("create_quick_record", {
|
||||||
id: record.id,
|
id: record.id,
|
||||||
});
|
});
|
||||||
self.model.unsetDirty(self.handle);
|
self.model.unsetDirty(self.handle);
|
||||||
self._updateButtons();
|
//self._updateButtons();
|
||||||
self.trigger_up("restore_flip_card");
|
self._enableQuickCreate();
|
||||||
|
},
|
||||||
|
block: true,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
_remove: function () {
|
_remove: function () {
|
||||||
this.trigger_up("restore_flip_card");
|
if (this._disabled) {
|
||||||
|
|
||||||
|
// Don't do anything if we are already creating a record
|
||||||
|
return $.Deferred();
|
||||||
|
}
|
||||||
|
|
||||||
|
this._disableQuickCreate();
|
||||||
|
this.trigger_up("restore_flip_card", {block: true});
|
||||||
|
var record = this.model.get(this.handle);
|
||||||
this.trigger_up("list_record_remove", {
|
this.trigger_up("list_record_remove", {
|
||||||
id: this.renderer.state.id,
|
id: record.id,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
_change: function () {
|
_change: function () {
|
||||||
|
var self = this;
|
||||||
|
if (this._disabled) {
|
||||||
|
|
||||||
|
// Don't do anything if we are already creating a record
|
||||||
|
return $.Deferred();
|
||||||
|
}
|
||||||
|
this._disableQuickCreate();
|
||||||
this.model.updateRecordContext(this.handle, {
|
this.model.updateRecordContext(this.handle, {
|
||||||
has_changes_confirmed: true,
|
has_changes_confirmed: true,
|
||||||
});
|
});
|
||||||
var record = this.model.get(this.handle);
|
var record = this.model.get(this.handle);
|
||||||
this.trigger_up("update_quick_record", {
|
|
||||||
|
this.trigger_up("restore_flip_card", {
|
||||||
|
success_callback: function () {
|
||||||
|
self.trigger_up("update_quick_record", {
|
||||||
id: record.id,
|
id: record.id,
|
||||||
});
|
});
|
||||||
this.trigger_up("restore_flip_card");
|
self.model.unsetDirty(self.handle);
|
||||||
this.model.unsetDirty(this.handle);
|
//self._updateButtons();
|
||||||
this._updateButtons();
|
self._enableQuickCreate();
|
||||||
|
},
|
||||||
|
block: true,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
_discard: function () {
|
_discard: function () {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
if (this._disabled) {
|
||||||
|
|
||||||
|
// Don't do anything if we are already creating a record
|
||||||
|
return $.Deferred();
|
||||||
|
}
|
||||||
|
this._disableQuickCreate();
|
||||||
var record = this.model.get(this.handle);
|
var record = this.model.get(this.handle);
|
||||||
this.model.discardChanges(this.handle, {
|
this.model.discardChanges(this.handle, {
|
||||||
rollback: true,
|
rollback: true,
|
||||||
|
@ -295,11 +329,13 @@ odoo.define("web_widget_one2many_product_picker.ProductPickerQuickCreateFormView
|
||||||
this.update({}, {reload: false});
|
this.update({}, {reload: false});
|
||||||
this.trigger_up("restore_flip_card");
|
this.trigger_up("restore_flip_card");
|
||||||
this._updateButtons();
|
this._updateButtons();
|
||||||
|
this._enableQuickCreate();
|
||||||
} else {
|
} else {
|
||||||
this.update({}, {reload: false}).then(function () {
|
this.update({}, {reload: false}).then(function () {
|
||||||
self.model.unsetDirty(self.handle);
|
self.model.unsetDirty(self.handle);
|
||||||
self.trigger_up("restore_flip_card");
|
self.trigger_up("restore_flip_card");
|
||||||
self._updateButtons();
|
self._updateButtons();
|
||||||
|
self._enableQuickCreate();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -13,6 +13,7 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
|
||||||
var tools = require("web_widget_one2many_product_picker.tools");
|
var tools = require("web_widget_one2many_product_picker.tools");
|
||||||
var ProductPickerQuickModifPriceForm = require(
|
var ProductPickerQuickModifPriceForm = require(
|
||||||
"web_widget_one2many_product_picker.ProductPickerQuickModifPriceForm");
|
"web_widget_one2many_product_picker.ProductPickerQuickModifPriceForm");
|
||||||
|
var FieldManagerMixin = require('web.FieldManagerMixin');
|
||||||
|
|
||||||
var qweb = core.qweb;
|
var qweb = core.qweb;
|
||||||
var _t = core._t;
|
var _t = core._t;
|
||||||
|
@ -42,6 +43,8 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
|
||||||
front: [],
|
front: [],
|
||||||
back: [],
|
back: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this._lazyUpdateRecord = _.debounce(this._updateRecord.bind(this), 450);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -105,6 +108,7 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
|
||||||
if (state) {
|
if (state) {
|
||||||
this._setState(state);
|
this._setState(state);
|
||||||
}
|
}
|
||||||
|
this.$card.removeClass("blocked");
|
||||||
// Avoid recreate active record
|
// Avoid recreate active record
|
||||||
if (this.$card.hasClass("active")) {
|
if (this.$card.hasClass("active")) {
|
||||||
this._processDynamicFields();
|
this._processDynamicFields();
|
||||||
|
@ -177,6 +181,7 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
|
||||||
this.fields = this.getParent().state.fields;
|
this.fields = this.getParent().state.fields;
|
||||||
this.fieldsInfo = this.getParent().state.fieldsInfo.form;
|
this.fieldsInfo = this.getParent().state.fieldsInfo.form;
|
||||||
this.state = viewState;
|
this.state = viewState;
|
||||||
|
|
||||||
if (recordSearch) {
|
if (recordSearch) {
|
||||||
this.recordSearch = recordSearch;
|
this.recordSearch = recordSearch;
|
||||||
}
|
}
|
||||||
|
@ -193,6 +198,8 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
|
||||||
// Using directly the 'model record' instead of the state because
|
// Using directly the 'model record' instead of the state because
|
||||||
// the state it's a parsed version of this record that doesn't
|
// the state it's a parsed version of this record that doesn't
|
||||||
// contains the '_virtual' attribute.
|
// contains the '_virtual' attribute.
|
||||||
|
var model = this.options.basicFieldParams.model;
|
||||||
|
var record = model.get(this.state.id);
|
||||||
return {
|
return {
|
||||||
record_search: this.recordSearch,
|
record_search: this.recordSearch,
|
||||||
user_context: this.getSession() && this.getSession().user_context || {},
|
user_context: this.getSession() && this.getSession().user_context || {},
|
||||||
|
@ -204,6 +211,7 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
|
||||||
monetary: this._getMonetaryFieldValue.bind(this),
|
monetary: this._getMonetaryFieldValue.bind(this),
|
||||||
show_discount: this.options.showDiscount,
|
show_discount: this.options.showDiscount,
|
||||||
is_virtual: this.is_virtual,
|
is_virtual: this.is_virtual,
|
||||||
|
modified: record && record.context.product_picker_modified,
|
||||||
active_model: '',
|
active_model: '',
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -497,6 +505,93 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
_saveRecord: function () {
|
||||||
|
var self = this;
|
||||||
|
var model = this.options.basicFieldParams.model;
|
||||||
|
var record = model.get(this.state.id);
|
||||||
|
return model.save(record.id, {
|
||||||
|
savePoint: true,
|
||||||
|
}).then(function () {
|
||||||
|
var record = model.get(self.state.id);
|
||||||
|
self.trigger_up("create_quick_record", {
|
||||||
|
id: record.id,
|
||||||
|
});
|
||||||
|
model.unsetDirty(self.state.id);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_updateRecord: function (changes) {
|
||||||
|
var model = this.options.basicFieldParams.model;
|
||||||
|
var record = model.get(this.state.id);
|
||||||
|
this.trigger_up("update_quick_record", {
|
||||||
|
id: record.id,
|
||||||
|
});
|
||||||
|
model.unsetDirty(this.state.id);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
_addProduct: function () {
|
||||||
|
var self = this;
|
||||||
|
var changes = {};
|
||||||
|
if (this.state.data[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(this.state.id, changes).then(function () {
|
||||||
|
self._saveRecord();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {Number} amount
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
_incProductQty: function (amount) {
|
||||||
|
var self = this;
|
||||||
|
this.state.data[this.options.fieldMap.product_uom_qty] += amount;
|
||||||
|
var model = this.options.basicFieldParams.model;
|
||||||
|
var record = model.get(this.state.id);
|
||||||
|
var state_data = record.data;
|
||||||
|
state_data[this.options.fieldMap.product_uom_qty] += amount;
|
||||||
|
var changes = _.pick(state_data, this.options.fieldMap.product_uom_qty);
|
||||||
|
|
||||||
|
return model.notifyChanges(record.id, changes).then(function () {
|
||||||
|
self._processDynamicFields();
|
||||||
|
self._lazyUpdateRecord();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_doInteractAnim: function (target, currentTarget) {
|
||||||
|
var $target = $(target);
|
||||||
|
var $currentTarget = $(currentTarget);
|
||||||
|
var $img = $currentTarget.find(".oe_flip_card_front img");
|
||||||
|
$target.addClass('o_catch_attention');
|
||||||
|
$target.on('animationend', function () {
|
||||||
|
$target.removeClass('o_catch_attention');
|
||||||
|
$target.off('animationend');
|
||||||
|
});
|
||||||
|
$img.addClass('oe_product_picker_catch_attention');
|
||||||
|
$img.on('animationend', function () {
|
||||||
|
$img.removeClass('oe_product_picker_catch_attention');
|
||||||
|
$img.off('animationend');
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
|
@ -531,11 +626,31 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
|
||||||
* @param {ClickEvent} evt
|
* @param {ClickEvent} evt
|
||||||
*/
|
*/
|
||||||
_onClickFlipCard: function (evt) {
|
_onClickFlipCard: function (evt) {
|
||||||
|
|
||||||
// Avoid clicks on form elements
|
// Avoid clicks on form elements
|
||||||
if (['INPUT', 'BUTTON', 'A'].indexOf(evt.target.tagName) !== -1) {
|
if (['INPUT', 'BUTTON', 'A'].indexOf(evt.target.tagName) !== -1 || this.$card.hasClass('blocked')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
var $target = $(evt.target);
|
||||||
|
if (!this.options.readOnlyMode) {
|
||||||
|
if (
|
||||||
|
$target.hasClass('add_product') ||
|
||||||
|
$target.parents('.add_product').length
|
||||||
|
) {
|
||||||
|
if (!this.is_adding_product) {
|
||||||
|
this.is_adding_product = true;
|
||||||
|
this._addProduct();
|
||||||
|
this._doInteractAnim(evt.target, evt.currentTarget);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else if (
|
||||||
|
$target.hasClass('product_qty') ||
|
||||||
|
$target.parents('.product_qty').length
|
||||||
|
) {
|
||||||
|
this._incProductQty(1);
|
||||||
|
this._doInteractAnim(evt.target, evt.currentTarget);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!this._clickFlipCardDelayed) {
|
if (!this._clickFlipCardDelayed) {
|
||||||
this._clickFlipCardDelayed = setTimeout(
|
this._clickFlipCardDelayed = setTimeout(
|
||||||
this._onClickDelayedFlipCard.bind(this, evt),
|
this._onClickDelayedFlipCard.bind(this, evt),
|
||||||
|
@ -644,7 +759,7 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_onRestoreFlipCard: function () {
|
_onRestoreFlipCard: function (evt) {
|
||||||
var self = this;
|
var self = this;
|
||||||
this.$card.removeClass("active");
|
this.$card.removeClass("active");
|
||||||
this.$front.removeClass("d-none");
|
this.$front.removeClass("d-none");
|
||||||
|
@ -660,7 +775,16 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
|
||||||
zIndex: "",
|
zIndex: "",
|
||||||
});
|
});
|
||||||
self.$card.off('transitionend');
|
self.$card.off('transitionend');
|
||||||
|
if (evt.data.success_callback) {
|
||||||
|
evt.data.success_callback();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
} else if (evt.data.success_callback) {
|
||||||
|
evt.data.success_callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (evt.data.block) {
|
||||||
|
this.$card.addClass("blocked");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -104,14 +104,12 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRenderer",
|
||||||
*/
|
*/
|
||||||
updateState: function (state, params) {
|
updateState: function (state, params) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
var sparams = _.extend({}, params, {noRender: true});
|
||||||
if (_.isEqual(this.state.data, state.data)) {
|
if (_.isEqual(this.state.data, state.data)) {
|
||||||
return this._super.apply(this, arguments);
|
return this._super(state, sparams);
|
||||||
}
|
}
|
||||||
var old_state = _.clone(this.state.data);
|
var old_state = _.clone(this.state.data);
|
||||||
return this._super(
|
return this._super(state, sparams).then(function () {
|
||||||
state,
|
|
||||||
_.extend({}, params, {noRender: true})
|
|
||||||
).then(function () {
|
|
||||||
self._updateStateRecords(old_state);
|
self._updateStateRecords(old_state);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -151,6 +149,7 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRenderer",
|
||||||
var widget = this.widgets[eb];
|
var widget = this.widgets[eb];
|
||||||
if (
|
if (
|
||||||
widget &&
|
widget &&
|
||||||
|
widget.state &&
|
||||||
widget.state.data[this.options.field_map.product].data.id === widget_product_id
|
widget.state.data[this.options.field_map.product].data.id === widget_product_id
|
||||||
) {
|
) {
|
||||||
found = true;
|
found = true;
|
||||||
|
@ -194,7 +193,7 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRenderer",
|
||||||
var found = false;
|
var found = false;
|
||||||
for (var e in this.state.data) {
|
for (var e in this.state.data) {
|
||||||
var current_state = this.state.data[e];
|
var current_state = this.state.data[e];
|
||||||
if (current_state.id === old_state.id) {
|
if (current_state.id === old_state.id || (typeof current_state.data.id !== 'undefined' && current_state.data.id === old_state.data.id)) {
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -203,6 +202,7 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRenderer",
|
||||||
states_to_destroy.push(old_state);
|
states_to_destroy.push(old_state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this._removeRecords(states_to_destroy);
|
this._removeRecords(states_to_destroy);
|
||||||
|
|
||||||
// Records to Update or Create
|
// Records to Update or Create
|
||||||
|
@ -215,12 +215,12 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRenderer",
|
||||||
var search_record = false;
|
var search_record = false;
|
||||||
for (var e = this.widgets.length-1; e>=0; --e) {
|
for (var e = this.widgets.length-1; e>=0; --e) {
|
||||||
var widget = this.widgets[e];
|
var widget = this.widgets[e];
|
||||||
if (!widget) {
|
if (!widget || !widget.state) {
|
||||||
|
|
||||||
// Already processed widget (deleted)
|
// Already processed widget (deleted)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (widget.state.id === state.id) {
|
if (widget.state.id === state.id || (typeof state.data.id !== 'undefined' && widget.state.data.id === state.data.id)) {
|
||||||
widget.recreate(state);
|
widget.recreate(state);
|
||||||
exists = true;
|
exists = true;
|
||||||
break;
|
break;
|
||||||
|
@ -236,8 +236,7 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRenderer",
|
||||||
// Remove "pure virtual" records that have the same product that the new record
|
// Remove "pure virtual" records that have the same product that the new record
|
||||||
if (
|
if (
|
||||||
widget.is_virtual &&
|
widget.is_virtual &&
|
||||||
widget.state.data[this.options.field_map.product].data.id === state.data[this.options.field_map.product].data.id &&
|
widget.state.data[this.options.field_map.product].data.id === state.data[this.options.field_map.product].data.id
|
||||||
widget.state.data[this.options.compa].data.id === state.data[this.options.field_map.product].data.id
|
|
||||||
) {
|
) {
|
||||||
to_destroy.push(widget);
|
to_destroy.push(widget);
|
||||||
delete this.widgets[e];
|
delete this.widgets[e];
|
||||||
|
@ -284,7 +283,8 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRenderer",
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compare search results with current lines
|
* Compare search results with current lines.
|
||||||
|
* Link a current state with the 'search record'.
|
||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
* @param {Array[Object]} results
|
* @param {Array[Object]} results
|
||||||
|
|
|
@ -580,11 +580,20 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
|
||||||
* @param {CustomEvent} evt
|
* @param {CustomEvent} evt
|
||||||
*/
|
*/
|
||||||
_onCreateQuickRecord: function (evt) {
|
_onCreateQuickRecord: function (evt) {
|
||||||
|
var self = this;
|
||||||
this.parent_controller.model.setPureVirtual(evt.data.id, false);
|
this.parent_controller.model.setPureVirtual(evt.data.id, false);
|
||||||
this._setValue({operation: "ADD", id: evt.data.id});
|
if (!self.options.auto_save) {
|
||||||
if (this.options.auto_save) {
|
self.parent_controller.model.updateRecordContext(evt.data.id, {
|
||||||
this.parent_controller.saveRecord(undefined, {stayInEdit: true});
|
product_picker_modified: true,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
this._setValue({operation: "ADD", id: evt.data.id}).then(function () {
|
||||||
|
if (self.options.auto_save) {
|
||||||
|
self.parent_controller.saveRecord(undefined, {stayInEdit: true}).then(function () {
|
||||||
|
self.renderer.updateState(self.value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -594,10 +603,19 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
|
||||||
* @param {CustomEevent} evt
|
* @param {CustomEevent} evt
|
||||||
*/
|
*/
|
||||||
_onUpdateQuickRecord: function (evt) {
|
_onUpdateQuickRecord: function (evt) {
|
||||||
this._setValue({operation: "UPDATE", id: evt.data.id, data: evt.data.data});
|
var self = this;
|
||||||
if (this.options.auto_save) {
|
if (!self.options.auto_save) {
|
||||||
this.parent_controller.saveRecord(undefined, {stayInEdit: true});
|
self.parent_controller.model.updateRecordContext(evt.data.id, {
|
||||||
|
product_picker_modified: true,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
this._setValue({operation: "UPDATE", id: evt.data.id, data: evt.data.data}).then(function () {
|
||||||
|
if (self.options.auto_save) {
|
||||||
|
self.parent_controller.saveRecord(undefined, {stayInEdit: true}).then(function () {
|
||||||
|
self.renderer.updateState(self.value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -59,6 +59,10 @@
|
||||||
transition: top $one2many-product-picker-transition-3d-time, left $one2many-product-picker-transition-3d-time, width $one2many-product-picker-transition-3d-time, height $one2many-product-picker-transition-3d-time;
|
transition: top $one2many-product-picker-transition-3d-time, left $one2many-product-picker-transition-3d-time, width $one2many-product-picker-transition-3d-time, height $one2many-product-picker-transition-3d-time;
|
||||||
height: $one2many-product-picker-card-min-height;
|
height: $one2many-product-picker-card-min-height;
|
||||||
|
|
||||||
|
&.blocked {
|
||||||
|
filter: blur(2px);
|
||||||
|
}
|
||||||
|
|
||||||
&.disabled {
|
&.disabled {
|
||||||
filter: grayscale(100%);
|
filter: grayscale(100%);
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
|
@ -211,6 +215,9 @@
|
||||||
font-size: 0.95rem;
|
font-size: 0.95rem;
|
||||||
z-index: 0;
|
z-index: 0;
|
||||||
}
|
}
|
||||||
|
.add_product, .product_qty, .price_unit {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -230,3 +237,20 @@
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.oe_product_picker_catch_attention {
|
||||||
|
position: relative;
|
||||||
|
animation: productPickerCatchAttention 200ms normal forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes productPickerCatchAttention {
|
||||||
|
0% {
|
||||||
|
transform: scale(1.0);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: scale(1.5);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: scale(1.0);
|
||||||
|
}
|
||||||
|
}
|
|
@ -72,11 +72,16 @@
|
||||||
<div class="oe_flip_container p-1 col-4 col-sm-4 col-md-2 col-lg-2 col-xl-1">
|
<div class="oe_flip_container p-1 col-4 col-sm-4 col-md-2 col-lg-2 col-xl-1">
|
||||||
<div t-attf-class="oe_flip_card {{!state && 'disabled' || ''}}">
|
<div t-attf-class="oe_flip_card {{!state && 'disabled' || ''}}">
|
||||||
<div class="oe_flip_card_inner text-center">
|
<div class="oe_flip_card_inner text-center">
|
||||||
<div t-attf-class="oe_flip_card_front p-0 {{state && !is_virtual && 'border-primary' || ''}}">
|
<div t-attf-class="oe_flip_card_front p-0 {{(modified && 'border-warning') || (state && !is_virtual && 'border-success') || ''}}">
|
||||||
<t t-if="state">
|
<t t-if="state">
|
||||||
<t t-if="!is_virtual">
|
<t t-if="!is_virtual">
|
||||||
<div class="position-absolute m-0 text-left">
|
<div class="position-absolute m-0 text-left">
|
||||||
<span t-att-data-field="field_map.product_uom_qty" t-attf-data-esc="str({{field_map.product_uom_qty}}) + ' x ' + {{field_map.product_uom}}.data.display_name" class="badge badge-primary font-weight-bold rounded-0 mt-1 p-2" />
|
<span t-att-data-field="field_map.product_uom_qty" t-attf-data-esc="str({{field_map.product_uom_qty}}) + ' x ' + {{field_map.product_uom}}.data.display_name" t-attf-class="badge {{modified && 'badge-warning' || 'badge-success'}} font-weight-bold rounded-0 mt-1 p-2 product_qty" />
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
<t t-else="">
|
||||||
|
<div class="position-absolute m-0 text-left">
|
||||||
|
<span class="badge badge-primary font-weight-bold rounded-0 mt-1 p-2 add_product"><i class="fa fa-plus"></i> Add 1 <t t-esc="state.data[field_map.product_uom].data.display_name"/></span>
|
||||||
</div>
|
</div>
|
||||||
</t>
|
</t>
|
||||||
<div class="position-absolute m-0 text-left badge_price">
|
<div class="position-absolute m-0 text-left badge_price">
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<t t-name="One2ManyProductPicker.QuickCreate.FormButtons">
|
<t t-name="One2ManyProductPicker.QuickCreate.FormButtons">
|
||||||
<div class="oe_one2many_product_picker_form_buttons">
|
<div class="oe_one2many_product_picker_form_buttons">
|
||||||
<t t-if="state == 'new'">
|
<t t-if="state == 'new'">
|
||||||
<button class="btn btn-primary oe_record_add">Add</button>
|
<button t-attf-class="btn btn-primary oe_record_add">Add</button>
|
||||||
</t>
|
</t>
|
||||||
<t t-elif="state == 'dirty'">
|
<t t-elif="state == 'dirty'">
|
||||||
<button class="btn btn-success oe_record_change mr-2"><i class="fa fa-check" /></button>
|
<button class="btn btn-success oe_record_change mr-2"><i class="fa fa-check" /></button>
|
||||||
|
|
Loading…
Reference in New Issue