mirror of https://github.com/OCA/web.git
[MIG] web_widget_one2many_tree_line_duplicate: Migration to 16.0
parent
5229e9910b
commit
f239c3c5d3
|
@ -7,7 +7,7 @@ Web Widget One2many Tree Line Duplicate
|
|||
!! This file is generated by oca-gen-addon-readme !!
|
||||
!! changes will be overwritten. !!
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
!! source digest: sha256:9cd7a43eab907d7d3ed3380c20cda1be40d288c01feb25dd54108e69cb350314
|
||||
!! source digest: sha256:0a96e20808687d52d22565143495374cad5121234c141e804bf8b9f06f9616d4
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
|
||||
|
@ -17,13 +17,13 @@ Web Widget One2many Tree Line Duplicate
|
|||
: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/13.0/web_widget_one2many_tree_line_duplicate
|
||||
:target: https://github.com/OCA/web/tree/16.0/web_widget_one2many_tree_line_duplicate
|
||||
:alt: OCA/web
|
||||
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
|
||||
:target: https://translation.odoo-community.org/projects/web-13-0/web-13-0-web_widget_one2many_tree_line_duplicate
|
||||
:target: https://translation.odoo-community.org/projects/web-16-0/web-16-0-web_widget_one2many_tree_line_duplicate
|
||||
:alt: Translate me on Weblate
|
||||
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
|
||||
:target: https://runboat.odoo-community.org/builds?repo=OCA/web&target_branch=13.0
|
||||
:target: https://runboat.odoo-community.org/builds?repo=OCA/web&target_branch=16.0
|
||||
:alt: Try me on Runboat
|
||||
|
||||
|badge1| |badge2| |badge3| |badge4| |badge5|
|
||||
|
@ -61,7 +61,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 to smash it by providing a detailed and welcomed
|
||||
`feedback <https://github.com/OCA/web/issues/new?body=module:%20web_widget_one2many_tree_line_duplicate%0Aversion:%2013.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_tree_line_duplicate%0Aversion:%2016.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.
|
||||
|
||||
|
@ -79,6 +79,7 @@ Contributors
|
|||
* `Tecnativa <https://www.tecnativa.com/>`_:
|
||||
|
||||
* Alexandre Díaz
|
||||
* Carlos Roca
|
||||
|
||||
Maintainers
|
||||
~~~~~~~~~~~
|
||||
|
@ -93,6 +94,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/13.0/web_widget_one2many_tree_line_duplicate>`_ project on GitHub.
|
||||
This module is part of the `OCA/web <https://github.com/OCA/web/tree/16.0/web_widget_one2many_tree_line_duplicate>`_ project on GitHub.
|
||||
|
||||
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
|
||||
|
|
|
@ -4,12 +4,22 @@
|
|||
{
|
||||
"name": "Web Widget One2many Tree Line Duplicate",
|
||||
"category": "web",
|
||||
"version": "13.0.1.0.2",
|
||||
"version": "16.0.1.0.0",
|
||||
"author": "Tecnativa, Odoo Community Association (OCA)",
|
||||
"license": "AGPL-3",
|
||||
"website": "https://github.com/OCA/web",
|
||||
"depends": ["web"],
|
||||
"data": ["view/assets.xml"],
|
||||
"auto_install": False,
|
||||
"installable": True,
|
||||
"assets": {
|
||||
"web.assets_backend": [
|
||||
"/web_widget_one2many_tree_line_duplicate/static/src/legacy/**/*.js",
|
||||
"/web_widget_one2many_tree_line_duplicate/static/src/**/*.esm.js",
|
||||
(
|
||||
"after",
|
||||
"/web/static/src/views/list/list_renderer.xml",
|
||||
"/web_widget_one2many_tree_line_duplicate/static/src/list/list_renderer.xml",
|
||||
),
|
||||
],
|
||||
},
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
* `Tecnativa <https://www.tecnativa.com/>`_:
|
||||
|
||||
* Alexandre Díaz
|
||||
* Carlos Roca
|
||||
|
|
|
@ -9,10 +9,11 @@
|
|||
|
||||
/*
|
||||
:Author: David Goodger (goodger@python.org)
|
||||
:Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $
|
||||
:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $
|
||||
:Copyright: This stylesheet has been placed in the public domain.
|
||||
|
||||
Default cascading style sheet for the HTML output of Docutils.
|
||||
Despite the name, some widely supported CSS2 features are used.
|
||||
|
||||
See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to
|
||||
customize this style sheet.
|
||||
|
@ -275,7 +276,7 @@ pre.literal-block, pre.doctest-block, pre.math, pre.code {
|
|||
margin-left: 2em ;
|
||||
margin-right: 2em }
|
||||
|
||||
pre.code .ln { color: grey; } /* line numbers */
|
||||
pre.code .ln { color: gray; } /* line numbers */
|
||||
pre.code, code { background-color: #eeeeee }
|
||||
pre.code .comment, code .comment { color: #5C6576 }
|
||||
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
|
||||
|
@ -301,7 +302,7 @@ span.option {
|
|||
span.pre {
|
||||
white-space: pre }
|
||||
|
||||
span.problematic {
|
||||
span.problematic, pre.problematic {
|
||||
color: red }
|
||||
|
||||
span.section-subtitle {
|
||||
|
@ -367,9 +368,9 @@ ul.auto-toc {
|
|||
!! This file is generated by oca-gen-addon-readme !!
|
||||
!! changes will be overwritten. !!
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
!! source digest: sha256:9cd7a43eab907d7d3ed3380c20cda1be40d288c01feb25dd54108e69cb350314
|
||||
!! source digest: sha256:0a96e20808687d52d22565143495374cad5121234c141e804bf8b9f06f9616d4
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
|
||||
<p><a class="reference external image-reference" 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 image-reference" 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 image-reference" href="https://github.com/OCA/web/tree/13.0/web_widget_one2many_tree_line_duplicate"><img alt="OCA/web" src="https://img.shields.io/badge/github-OCA%2Fweb-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/web-13-0/web-13-0-web_widget_one2many_tree_line_duplicate"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/web&target_branch=13.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
|
||||
<p><a class="reference external image-reference" 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 image-reference" 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 image-reference" href="https://github.com/OCA/web/tree/16.0/web_widget_one2many_tree_line_duplicate"><img alt="OCA/web" src="https://img.shields.io/badge/github-OCA%2Fweb-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/web-16-0/web-16-0-web_widget_one2many_tree_line_duplicate"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/web&target_branch=16.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
|
||||
<p>Allow to add a icon to clone the line.</p>
|
||||
<p><strong>Table of contents</strong></p>
|
||||
<div class="contents local topic" id="contents">
|
||||
|
@ -408,7 +409,7 @@ ul.auto-toc {
|
|||
<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 to smash it by providing a detailed and welcomed
|
||||
<a class="reference external" href="https://github.com/OCA/web/issues/new?body=module:%20web_widget_one2many_tree_line_duplicate%0Aversion:%2013.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_tree_line_duplicate%0Aversion:%2016.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">
|
||||
|
@ -424,6 +425,7 @@ If you spotted it first, help us to smash it by providing a detailed and welcome
|
|||
<ul class="simple">
|
||||
<li><a class="reference external" href="https://www.tecnativa.com/">Tecnativa</a>:<ul>
|
||||
<li>Alexandre Díaz</li>
|
||||
<li>Carlos Roca</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
@ -431,11 +433,13 @@ If you spotted it first, help us to smash it by providing a detailed and welcome
|
|||
<div class="section" id="maintainers">
|
||||
<h2><a class="toc-backref" href="#toc-entry-7">Maintainers</a></h2>
|
||||
<p>This module is maintained by the OCA.</p>
|
||||
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a>
|
||||
<a class="reference external image-reference" href="https://odoo-community.org">
|
||||
<img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" />
|
||||
</a>
|
||||
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose
|
||||
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/13.0/web_widget_one2many_tree_line_duplicate">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/16.0/web_widget_one2many_tree_line_duplicate">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>
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
/** @odoo-module **/
|
||||
/* Copyright 2024 Tecnativa - Carlos Roca
|
||||
* License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). */
|
||||
|
||||
import {StaticList} from "@web/views/basic_relational_model";
|
||||
import {patch} from "@web/core/utils/patch";
|
||||
|
||||
patch(StaticList.prototype, "web_widget_one2many_tree_line_duplicate.StaticList", {
|
||||
async cloneRecord(recordId, params) {
|
||||
const operation = {
|
||||
context: [params.context],
|
||||
operation: "CLONE",
|
||||
position: "bottom",
|
||||
id: recordId,
|
||||
};
|
||||
await this.model.__bm__.save(this.__bm_handle__, {savePoint: true});
|
||||
this.model.__bm__.freezeOrder(this.__bm_handle__);
|
||||
await this.__syncParent(operation);
|
||||
const newRecord = this.records[this.records.length - 1];
|
||||
return newRecord;
|
||||
},
|
||||
});
|
|
@ -1,163 +0,0 @@
|
|||
/* Copyright 2021 Tecnativa - Alexandre Díaz
|
||||
* License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) */
|
||||
|
||||
odoo.define(
|
||||
"web_widget_one2many_tree_line_duplicate.One2manyTreeLineDuplicate",
|
||||
function (require) {
|
||||
"use strict";
|
||||
|
||||
const core = require("web.core");
|
||||
const FieldOne2Many = require("web.relational_fields").FieldOne2Many;
|
||||
const ListRenderer = require("web.ListRenderer");
|
||||
|
||||
const _t = core._t;
|
||||
|
||||
ListRenderer.include({
|
||||
events: _.extend({}, ListRenderer.prototype.events, {
|
||||
"click tr .o_list_record_clone": "_onCloneIconClick",
|
||||
}),
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
init: function (parent) {
|
||||
this._super.apply(this, arguments);
|
||||
let allow_clone =
|
||||
parent.attrs &&
|
||||
parent.attrs.options &&
|
||||
parent.attrs.options.allow_clone;
|
||||
allow_clone = typeof allow_clone === "undefined" ? false : allow_clone;
|
||||
this.addCloneIcon =
|
||||
allow_clone &&
|
||||
!parent.isReadonly &&
|
||||
parent.activeActions &&
|
||||
parent.activeActions.create;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @override
|
||||
*/
|
||||
_renderHeader: function () {
|
||||
var $thead = this._super.apply(this, arguments);
|
||||
if (this.addCloneIcon) {
|
||||
$thead
|
||||
.find("tr")
|
||||
.append($("<th>", {class: "o_list_record_clone_header"}));
|
||||
}
|
||||
return $thead;
|
||||
},
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @private
|
||||
*/
|
||||
_renderFooter: function () {
|
||||
const $footer = this._super.apply(this, arguments);
|
||||
if (this.addCloneIcon) {
|
||||
$footer.find("tr").append($("<td>"));
|
||||
}
|
||||
return $footer;
|
||||
},
|
||||
|
||||
/**
|
||||
* Inject the icon for clone action
|
||||
*
|
||||
* @private
|
||||
* @override
|
||||
*/
|
||||
_renderRow: function (record, index) {
|
||||
const $row = this._super.apply(this, arguments);
|
||||
if (this.addCloneIcon) {
|
||||
const $icon = $("<button>", {
|
||||
class: "fa fa-clone",
|
||||
name: "clone",
|
||||
"aria-label": _t("Clone row ") + (index + 1),
|
||||
});
|
||||
const $td = $("<td>", {class: "o_list_record_clone"}).append($icon);
|
||||
$row.append($td);
|
||||
}
|
||||
return $row;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @override
|
||||
*/
|
||||
_getNumberOfCols: function () {
|
||||
var n = this._super();
|
||||
if (this.addCloneIcon) {
|
||||
n++;
|
||||
}
|
||||
return n;
|
||||
},
|
||||
|
||||
/**
|
||||
* Trigger the clonation of the record
|
||||
*
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
_onCloneIconClick: function (ev) {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
var $row = $(ev.target).closest("tr");
|
||||
var id = $row.data("id");
|
||||
this.unselectRow().then(() => {
|
||||
this.trigger_up("clone_record", {
|
||||
context: ev.currentTarget.dataset.context && [
|
||||
ev.currentTarget.dataset.context,
|
||||
],
|
||||
id: id,
|
||||
});
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
FieldOne2Many.include({
|
||||
custom_events: _.extend({}, FieldOne2Many.prototype.custom_events, {
|
||||
clone_record: "_onCloneRecord",
|
||||
}),
|
||||
|
||||
/**
|
||||
* @param {CustomEvent} ev
|
||||
*/
|
||||
_onCloneRecord: function (ev) {
|
||||
const data = ev.data || {};
|
||||
ev.stopPropagation();
|
||||
if (!this.cloningRecord && this.activeActions.create) {
|
||||
this.cloningRecord = true;
|
||||
this.trigger_up("edited_list", {id: this.value.id});
|
||||
this._setValue(
|
||||
{
|
||||
operation: "CLONE", // This operation is a special case implemented only in this module
|
||||
position: "bottom",
|
||||
context: data.context,
|
||||
id: ev.data.id,
|
||||
},
|
||||
{
|
||||
allowWarning: data.allowWarning,
|
||||
}
|
||||
)
|
||||
.then(() => {
|
||||
this.cloningRecord = false;
|
||||
})
|
||||
.then(() => {
|
||||
// This is necessary to propagate the changes
|
||||
// to the main record
|
||||
this._setValue({
|
||||
operation: "TRIGGER_ONCHANGE",
|
||||
});
|
||||
})
|
||||
.then(() => {
|
||||
if (data.onSuccess) {
|
||||
data.onSuccess();
|
||||
}
|
||||
})
|
||||
.guardedCatch(() => {
|
||||
this.cloningRecord = false;
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
);
|
|
@ -203,60 +203,81 @@ odoo.define("web_widget_one2many_tree_line_duplicate.BasicModel", function (requ
|
|||
return Promise.all(defs).then(() => _.keys(changes));
|
||||
},
|
||||
|
||||
/**
|
||||
* Modified implementation of '_performOnChange' to properly unfold the cloned
|
||||
* record properties son we can interact with it as if we'd created it. We
|
||||
* don't really do an onchange and the only fields that we're getting are those
|
||||
* relational.
|
||||
*
|
||||
* @param {Object} record
|
||||
* @param {String} [viewType] current viewType. If not set, we will assume
|
||||
* main viewType from the record
|
||||
* @returns {Promise}
|
||||
*/
|
||||
_pseudoOnChange: function (record, viewType) {
|
||||
var self = this;
|
||||
var onchangeSpec = this._buildOnchangeSpecs(record, viewType);
|
||||
if (!onchangeSpec) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
var idList = record.data.id ? [record.data.id] : [];
|
||||
var options = {
|
||||
full: true,
|
||||
};
|
||||
var context = this._getContext(record, options);
|
||||
var currentData = this._generateOnChangeData(record, {changesOnly: false});
|
||||
applyDefaultValues: function (recordID, values, options) {
|
||||
options = options || {};
|
||||
var record = this.localData[recordID];
|
||||
var viewType = options.viewType || record.viewType;
|
||||
var fieldNames =
|
||||
options.fieldNames || Object.keys(record.fieldsInfo[viewType]);
|
||||
record._changes = record._changes || {};
|
||||
|
||||
return self
|
||||
._rpc({
|
||||
model: record.model,
|
||||
method: "onchange",
|
||||
args: [idList, currentData, [], onchangeSpec],
|
||||
context: context,
|
||||
})
|
||||
.then(function (result) {
|
||||
if (!record._changes) {
|
||||
// If the _changes key does not exist anymore, it means that
|
||||
// it was removed by discarding the changes after the rpc
|
||||
// to onchange. So, in that case, the proper response is to
|
||||
// ignore the onchange.
|
||||
return;
|
||||
// Ignore values for non requested fields (for instance, fields that are
|
||||
// not in the view)
|
||||
values = _.pick(values, fieldNames);
|
||||
|
||||
// Fill default values for missing fields
|
||||
for (var i = 0; i < fieldNames.length; i++) {
|
||||
var fieldName = fieldNames[i];
|
||||
if (!(fieldName in values) && !(fieldName in record._changes)) {
|
||||
var field = record.fields[fieldName];
|
||||
if (
|
||||
field.type === "float" ||
|
||||
field.type === "integer" ||
|
||||
field.type === "monetary"
|
||||
) {
|
||||
values[fieldName] = 0;
|
||||
} else if (
|
||||
field.type === "one2many" ||
|
||||
field.type === "many2many"
|
||||
) {
|
||||
values[fieldName] = [];
|
||||
} else {
|
||||
values[fieldName] = null;
|
||||
}
|
||||
if (result.warning) {
|
||||
self.trigger_up("warning", result.warning);
|
||||
record._warning = true;
|
||||
}
|
||||
if (result.domain) {
|
||||
record._domains = _.extend(record._domains, result.domain);
|
||||
}
|
||||
// We're only interested in relational fields
|
||||
const values = _.pick(result.value, (v) => {
|
||||
return typeof v === "object";
|
||||
}
|
||||
}
|
||||
|
||||
// Parse each value and create dataPoints for relational fields
|
||||
var defs = [];
|
||||
for (var fieldName in values) {
|
||||
var field = record.fields[fieldName];
|
||||
record.data[fieldName] = null;
|
||||
if (field.type === "many2one" && values[fieldName]) {
|
||||
var dp = this._makeDataPoint({
|
||||
context: record.context,
|
||||
data: {id: values[fieldName]},
|
||||
modelName: field.relation,
|
||||
parentID: record.id,
|
||||
});
|
||||
return self._applyOnChange(values, record).then(function () {
|
||||
return result;
|
||||
record._changes[fieldName] = dp.id;
|
||||
} else if (field.type === "reference" && values[fieldName]) {
|
||||
var ref = values[fieldName].split(",");
|
||||
var dp = this._makeDataPoint({
|
||||
context: record.context,
|
||||
data: {id: parseInt(ref[1])},
|
||||
modelName: ref[0],
|
||||
parentID: record.id,
|
||||
});
|
||||
});
|
||||
defs.push(this._fetchNameGet(dp));
|
||||
record._changes[fieldName] = dp.id;
|
||||
} else if (field.type === "one2many" || field.type === "many2many") {
|
||||
defs.push(
|
||||
this._processX2ManyCommands(
|
||||
record,
|
||||
fieldName,
|
||||
values[fieldName],
|
||||
options
|
||||
)
|
||||
);
|
||||
} else {
|
||||
record._changes[fieldName] = this._parseServerValue(
|
||||
field,
|
||||
values[fieldName]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.all(defs);
|
||||
},
|
||||
|
||||
_makeCloneRecord: function (modelName, params, values) {
|
||||
|
@ -302,20 +323,6 @@ odoo.define("web_widget_one2many_tree_line_duplicate.BasicModel", function (requ
|
|||
record_parent_id: params.clone_parent_record_id,
|
||||
copy_data: params.clone_copy_data || values,
|
||||
};
|
||||
|
||||
// We want to overwrite the default value of the handle field (if any),
|
||||
// in order for new lines to be added at the correct position.
|
||||
// -> This is a rare case where the defaul_get from the server
|
||||
// will be ignored by the view for a certain field (usually "sequence").
|
||||
|
||||
var overrideDefaultFields = this._computeOverrideDefaultFields(
|
||||
params.parentID,
|
||||
params.position
|
||||
);
|
||||
|
||||
if (overrideDefaultFields) {
|
||||
values[overrideDefaultFields.field] = overrideDefaultFields.value;
|
||||
}
|
||||
const _this = this;
|
||||
return (
|
||||
this.applyDefaultValues(record.id, values, {fieldNames: fieldNames})
|
||||
|
@ -333,19 +340,45 @@ odoo.define("web_widget_one2many_tree_line_duplicate.BasicModel", function (requ
|
|||
resolve();
|
||||
};
|
||||
_this
|
||||
._pseudoOnChange(record, targetView)
|
||||
._performOnChange(record, [], {})
|
||||
.then(always)
|
||||
.guardedCatch(always);
|
||||
});
|
||||
return def;
|
||||
})
|
||||
.then(() => {
|
||||
return this._fetchRelationalData(record);
|
||||
})
|
||||
.then(() => {
|
||||
// Inject always_reload to many2one fieldsInfo
|
||||
for (var key of Object.keys(record.fieldsInfo[targetView])) {
|
||||
if (record.fields[key].type === "many2one") {
|
||||
const old_reload_value =
|
||||
record.fieldsInfo[targetView][key].options &&
|
||||
record.fieldsInfo[targetView][key].options
|
||||
.always_reload;
|
||||
record.fieldsInfo[targetView][key].options = {
|
||||
...record.fieldsInfo[targetView][key].options,
|
||||
always_reload: true,
|
||||
old_reload_value,
|
||||
};
|
||||
}
|
||||
}
|
||||
return this._postprocess(record);
|
||||
})
|
||||
.then(() => {
|
||||
// Recover always_reload state before injection to many2one fieldsInfo
|
||||
for (var key of Object.keys(record.fieldsInfo[targetView])) {
|
||||
if (
|
||||
record.fieldsInfo[targetView][key].options &&
|
||||
"old_reload_value" in
|
||||
record.fieldsInfo[targetView][key].options
|
||||
) {
|
||||
const old_reload_value =
|
||||
record.fieldsInfo[targetView][key].options
|
||||
.old_reload_value;
|
||||
record.fieldsInfo[targetView][
|
||||
key
|
||||
].options.always_reload = old_reload_value;
|
||||
}
|
||||
}
|
||||
// Save initial changes, so they can be restored later,
|
||||
// if we need to discard.
|
||||
this.save(record.id, {savePoint: true});
|
|
@ -0,0 +1,38 @@
|
|||
/** @odoo-module **/
|
||||
/* Copyright 2024 Tecnativa - Carlos Roca
|
||||
* License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). */
|
||||
|
||||
import {ListRenderer} from "@web/views/list/list_renderer";
|
||||
import {patch} from "@web/core/utils/patch";
|
||||
|
||||
patch(ListRenderer.prototype, "web_widget_one2many_tree_line_duplicate.ListRenderer", {
|
||||
setup() {
|
||||
this._super(...arguments);
|
||||
const parent = this.__owl__.parent.parent;
|
||||
this.displayDuplicateLine =
|
||||
parent &&
|
||||
parent.props &&
|
||||
parent.props.fieldInfo &&
|
||||
parent.props.fieldInfo.options &&
|
||||
parent.props.fieldInfo.options.allow_clone;
|
||||
},
|
||||
get nbCols() {
|
||||
var nbCols = this._super(...arguments);
|
||||
if (this.displayDuplicateLine) {
|
||||
nbCols++;
|
||||
}
|
||||
return nbCols;
|
||||
},
|
||||
async onCloneIconClick(record) {
|
||||
const editedRecord = this.props.list.editedRecord;
|
||||
if (editedRecord && editedRecord !== record) {
|
||||
const unselected = await this.props.list.unselectRecord(true);
|
||||
if (!unselected) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
const context = this.props.list.model.root.context;
|
||||
await this.props.list.cloneRecord(record.__bm_handle__, {context});
|
||||
this.props.list.model.notify();
|
||||
},
|
||||
});
|
|
@ -0,0 +1,43 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<templates xml:space="preserve">
|
||||
<t
|
||||
t-name="web_widget_one2many_tree_line_duplicate.ListRenderer"
|
||||
t-inherit="web.ListRenderer"
|
||||
t-inherit-mode="extension"
|
||||
owl="1"
|
||||
>
|
||||
<xpath
|
||||
expr="//th[@t-if='displayOptionalFields or activeActions.onDelete']"
|
||||
position="before"
|
||||
>
|
||||
<th
|
||||
t-if="displayDuplicateLine"
|
||||
class="o_list_controller o_list_actions_header position-static"
|
||||
style="width: 32px; min-width: 32px"
|
||||
/>
|
||||
</xpath>
|
||||
</t>
|
||||
<t
|
||||
t-name="web_widget_one2many_tree_line_duplicate.ListRenderer.RecordRow"
|
||||
t-inherit="web.ListRenderer.RecordRow"
|
||||
t-inherit-mode="extension"
|
||||
owl="1"
|
||||
>
|
||||
<xpath expr="//td[hasclass('o_list_record_remove')]" position="before">
|
||||
<td
|
||||
class="o_list_record_remove text-center"
|
||||
t-if="displayDuplicateLine"
|
||||
t-on-click.stop="() => this.onCloneIconClick(record)"
|
||||
tabindex="-1"
|
||||
>
|
||||
<button
|
||||
class="fa fa-clone"
|
||||
name="duplicate"
|
||||
aria-label="Duplicate row"
|
||||
tabindex="-1"
|
||||
/>
|
||||
</td>
|
||||
</xpath>
|
||||
</t>
|
||||
|
||||
</templates>
|
|
@ -1,22 +0,0 @@
|
|||
/* Copyright 2021 Tecnativa - Alexandre Díaz
|
||||
* License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) */
|
||||
|
||||
.o_list_view {
|
||||
.o_list_table {
|
||||
.o_list_record_clone {
|
||||
width: 1px; // to prevent the column to expand
|
||||
}
|
||||
|
||||
.o_list_record_clone button {
|
||||
padding: 0px;
|
||||
background: none;
|
||||
border-style: none;
|
||||
display: table-cell;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.o_list_record_clone_header {
|
||||
width: 32px;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<template id="assets_backend" inherit_id="web.assets_backend">
|
||||
<xpath expr="." position="inside">
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="/web_widget_one2many_tree_line_duplicate/static/src/scss/one2many_tree_line_duplicate.scss"
|
||||
/>
|
||||
</xpath>
|
||||
<xpath expr="//script[1]" position="before">
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="/web_widget_one2many_tree_line_duplicate/static/src/js/basic_model.js"
|
||||
/>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="/web_widget_one2many_tree_line_duplicate/static/src/js/one2many_tree_line_duplicate.js"
|
||||
/>
|
||||
</xpath>
|
||||
</template>
|
||||
</odoo>
|
Loading…
Reference in New Issue