mirror of
https://github.com/OCA/web.git
synced 2025-02-22 13:21:25 +02:00
[MIG] web_widget_one2many_product_picker: Migration to 13.0
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -107,4 +107,3 @@ msgstr ""
|
||||
#, python-format
|
||||
msgid "[No widget %s]"
|
||||
msgstr ""
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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()));
|
||||
});
|
||||
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 && state.id || record_search.id"
|
||||
>
|
||||
<div
|
||||
t-attf-class="oe_flip_card {{!state && 'disabled' || (auto_save && !is_virtual && !state.data.id && 'blocked') || ''}}"
|
||||
t-attf-class="oe_flip_card {{!state && 'disabled' || (auto_save && (!is_virtual || is_saving) && !state.data.id && 'blocked') || ''}}"
|
||||
>
|
||||
<div class="oe_flip_card_inner text-center">
|
||||
<div
|
||||
t-attf-class="oe_flip_card_front p-0 {{(modified && 'border-warning') || (state && !is_virtual && 'border-success') || ''}}"
|
||||
t-attf-class="oe_flip_card_front p-0 {{((modified || is_saving) && 'border-warning') || (state && !is_virtual && '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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user