diff --git a/addons/project/static/src/views/project_task_kanban/project_task_kanban_model.js b/addons/project/static/src/views/project_task_kanban/project_task_kanban_model.js
index 05d3e179f63..dd887ebac27 100644
--- a/addons/project/static/src/views/project_task_kanban/project_task_kanban_model.js
+++ b/addons/project/static/src/views/project_task_kanban/project_task_kanban_model.js
@@ -41,13 +41,13 @@ export class ProjectTaskKanbanDynamicGroupList extends RelationalModel.DynamicGr
}
export class ProjectTaskRecord extends RelationalModel.Record {
- async _update(changes, options) {
+ _update(changes, options) {
const value = changes.personal_stage_type_ids;
if (Array.isArray(value)) {
delete changes.personal_stage_type_ids;
changes.personal_stage_type_id = value;
}
- await super._update(changes, options);
+ return super._update(changes, options);
}
get context() {
diff --git a/addons/web/static/src/model/relational_model/dynamic_group_list.js b/addons/web/static/src/model/relational_model/dynamic_group_list.js
index 6d4d21cb77c..6dc4fa19ae6 100644
--- a/addons/web/static/src/model/relational_model/dynamic_group_list.js
+++ b/addons/web/static/src/model/relational_model/dynamic_group_list.js
@@ -116,10 +116,10 @@ export class DynamicGroupList extends DynamicList {
sourceGroup._addRecord(record, oldIndex);
};
try {
- await record.update({ [targetGroup.groupByField.name]: value });
- const res = await record.save({ noReload: true });
+ const changes = { [targetGroup.groupByField.name]: value };
+ const res = await record.update(changes, { save: true });
if (!res) {
- revert();
+ return revert();
}
} catch (e) {
// revert changes
diff --git a/addons/web/static/src/model/relational_model/record.js b/addons/web/static/src/model/relational_model/record.js
index f06ddc66898..450ac218a06 100644
--- a/addons/web/static/src/model/relational_model/record.js
+++ b/addons/web/static/src/model/relational_model/record.js
@@ -237,11 +237,11 @@ export class Record extends DataPoint {
return this.model.mutex.exec(() => this._toggleArchive(false));
}
- update(changes) {
+ update(changes, { save } = {}) {
if (this.model._urgentSave) {
- return this._update(changes);
+ return this._update(changes, { save: false }); // save is already scheduled
}
- return this.model.mutex.exec(() => this._update(changes));
+ return this.model.mutex.exec(() => this._update(changes, { save }));
}
urgentSave() {
@@ -913,7 +913,7 @@ export class Record extends DataPoint {
}
}
- async _update(changes, { withoutOnchange, withoutParentUpdate } = {}) {
+ async _update(changes, { withoutOnchange, withoutParentUpdate, save } = {}) {
this.dirty = true;
const prom = this._preprocessChanges(changes);
if (prom && !this.model._urgentSave) {
@@ -935,7 +935,7 @@ export class Record extends DataPoint {
const onChangeFields = Object.keys(changes).filter(
(fieldName) => this.activeFields[fieldName] && this.activeFields[fieldName].onChange
);
- if (onChangeFields.length && !this.model._urgentSave && !withoutOnchange) {
+ if (onChangeFields.length && !this.model._urgentSave && !withoutOnchange && !save) {
const localChanges = this._getChanges(
{ ...this._changes, ...changes },
{ withReadonly: true }
@@ -976,5 +976,8 @@ export class Record extends DataPoint {
}
await this.model.hooks.onRecordChanged(this, this._getChanges());
}
+ if (save) {
+ return this._save();
+ }
}
}
diff --git a/addons/web/static/src/views/fields/boolean_favorite/boolean_favorite_field.js b/addons/web/static/src/views/fields/boolean_favorite/boolean_favorite_field.js
index 44e2dbcef6e..20003f2d67b 100644
--- a/addons/web/static/src/views/fields/boolean_favorite/boolean_favorite_field.js
+++ b/addons/web/static/src/views/fields/boolean_favorite/boolean_favorite_field.js
@@ -19,10 +19,8 @@ export class BooleanFavoriteField extends Component {
};
async update() {
- await this.props.record.update({ [this.props.name]: !this.props.record.data[this.props.name] });
- if (this.props.autosave) {
- await this.props.record.save();
- }
+ const changes = { [this.props.name]: !this.props.record.data[this.props.name] };
+ await this.props.record.update(changes, { save: this.props.autosave });
}
}
diff --git a/addons/web/static/src/views/fields/boolean_toggle/boolean_toggle_field.js b/addons/web/static/src/views/fields/boolean_toggle/boolean_toggle_field.js
index ab8878bc513..6b9382bdba7 100644
--- a/addons/web/static/src/views/fields/boolean_toggle/boolean_toggle_field.js
+++ b/addons/web/static/src/views/fields/boolean_toggle/boolean_toggle_field.js
@@ -12,10 +12,8 @@ export class BooleanToggleField extends BooleanField {
};
async onChange(newValue) {
- await this.props.record.update({ [this.props.name]: newValue });
- if (this.props.autosave) {
- return this.props.record.save();
- }
+ const changes = { [this.props.name]: newValue };
+ await this.props.record.update(changes, { save: this.props.autosave });
}
}
diff --git a/addons/web/static/src/views/fields/boolean_toggle/list_boolean_toggle_field.js b/addons/web/static/src/views/fields/boolean_toggle/list_boolean_toggle_field.js
index cb62d2766bc..5dd7e8c5691 100644
--- a/addons/web/static/src/views/fields/boolean_toggle/list_boolean_toggle_field.js
+++ b/addons/web/static/src/views/fields/boolean_toggle/list_boolean_toggle_field.js
@@ -8,12 +8,8 @@ export class ListBooleanToggleField extends BooleanToggleField {
async onClick() {
if (!this.props.readonly && this.props.record.isInEdition) {
- await this.props.record.update({
- [this.props.name]: !this.props.record.data[this.props.name],
- });
- if (this.props.autosave) {
- return this.props.record.save();
- }
+ const changes = { [this.props.name]: !this.props.record.data[this.props.name] };
+ await this.props.record.update(changes, { save: this.props.autosave });
}
}
}
diff --git a/addons/web/static/src/views/fields/many2many_tags/many2many_tags_field.js b/addons/web/static/src/views/fields/many2many_tags/many2many_tags_field.js
index 273fe45af75..81f6a78b4df 100644
--- a/addons/web/static/src/views/fields/many2many_tags/many2many_tags_field.js
+++ b/addons/web/static/src/views/fields/many2many_tags/many2many_tags_field.js
@@ -352,10 +352,10 @@ export class Many2ManyTagsFieldColorEditable extends Many2ManyTagsField {
if (tagRecord.data[this.props.colorField] != 0) {
this.previousColorsMap[tagRecord.resId] = tagRecord.data[this.props.colorField];
}
- tagRecord.update({
+ const changes = {
[this.props.colorField]: isHidden ? 0 : this.previousColorsMap[tagRecord.resId] || 1,
- });
- tagRecord.save();
+ };
+ tagRecord.update(changes, { save: true });
this.popover.close();
}
@@ -363,8 +363,7 @@ export class Many2ManyTagsFieldColorEditable extends Many2ManyTagsField {
const tagRecord = this.props.record.data[this.props.name].records.find(
(record) => record.id === tag.id
);
- tagRecord.update({ [this.props.colorField]: colorIndex });
- tagRecord.save();
+ tagRecord.update({ [this.props.colorField]: colorIndex }, { save: true });
this.popover.close();
}
}
diff --git a/addons/web/static/src/views/fields/priority/priority_field.js b/addons/web/static/src/views/fields/priority/priority_field.js
index a33ef944035..a7a0bfb6336 100644
--- a/addons/web/static/src/views/fields/priority/priority_field.js
+++ b/addons/web/static/src/views/fields/priority/priority_field.js
@@ -82,10 +82,7 @@ export class PriorityField extends Component {
}
async updateRecord(value) {
- await this.props.record.update({ [this.props.name]: value });
- if (this.props.autosave) {
- return this.props.record.save();
- }
+ await this.props.record.update({ [this.props.name]: value }, { save: this.props.autosave });
}
}
diff --git a/addons/web/static/src/views/fields/progress_bar/progress_bar_field.js b/addons/web/static/src/views/fields/progress_bar/progress_bar_field.js
index 0833b61aa2b..068e261318b 100644
--- a/addons/web/static/src/views/fields/progress_bar/progress_bar_field.js
+++ b/addons/web/static/src/views/fields/progress_bar/progress_bar_field.js
@@ -75,10 +75,7 @@ export class ProgressBarField extends Component {
if (this.props.record.fields[fieldName].type === "integer") {
parsedValue = Math.floor(parsedValue);
}
- this.props.record.update({ [fieldName]: parsedValue });
- if (this.props.readonly) {
- this.props.record.save();
- }
+ this.props.record.update({ [fieldName]: parsedValue }, { save: this.props.readonly });
}
onCurrentValueChange(ev) {
this.onValueChange(ev.target.value, this.currentValueField);
diff --git a/addons/web/static/src/views/fields/state_selection/state_selection_field.js b/addons/web/static/src/views/fields/state_selection/state_selection_field.js
index c26a546f621..9ca6d39e577 100644
--- a/addons/web/static/src/views/fields/state_selection/state_selection_field.js
+++ b/addons/web/static/src/views/fields/state_selection/state_selection_field.js
@@ -71,10 +71,7 @@ export class StateSelectionField extends Component {
}
async updateRecord(value) {
- await this.props.record.update({ [this.props.name]: value });
- if (this.props.autosave) {
- return this.props.record.save();
- }
+ await this.props.record.update({ [this.props.name]: value }, { save: this.props.autosave });
}
}
diff --git a/addons/web/static/src/views/kanban/kanban_cover_image_dialog.js b/addons/web/static/src/views/kanban/kanban_cover_image_dialog.js
index 875e9873b77..8d7c85833ac 100644
--- a/addons/web/static/src/views/kanban/kanban_cover_image_dialog.js
+++ b/addons/web/static/src/views/kanban/kanban_cover_image_dialog.js
@@ -59,8 +59,7 @@ export class KanbanCoverImageDialog extends Component {
async setCover() {
const id = this.state.selectedAttachmentId ? [this.state.selectedAttachmentId] : false;
- await this.props.record.update({ [this.props.fieldName]: id });
- await this.props.record.save();
+ await this.props.record.update({ [this.props.fieldName]: id }, { save: true });
this.props.close();
}
diff --git a/addons/web/static/src/views/kanban/kanban_record.js b/addons/web/static/src/views/kanban/kanban_record.js
index ba0149dcfea..191845b201b 100644
--- a/addons/web/static/src/views/kanban/kanban_record.js
+++ b/addons/web/static/src/views/kanban/kanban_record.js
@@ -297,8 +297,7 @@ export class KanbanRecord extends Component {
async selectColor(colorIndex) {
const { archInfo, record } = this.props;
- await record.update({ [archInfo.colorField]: colorIndex });
- await record.save();
+ await record.update({ [archInfo.colorField]: colorIndex }, { save: true });
}
/**
diff --git a/addons/web/static/tests/views/fields/one2many_field_tests.js b/addons/web/static/tests/views/fields/one2many_field_tests.js
index 70fda3e135b..53486d9ae87 100644
--- a/addons/web/static/tests/views/fields/one2many_field_tests.js
+++ b/addons/web/static/tests/views/fields/one2many_field_tests.js
@@ -13097,12 +13097,7 @@ QUnit.module("Fields", (hooks) => {
assert.verifySteps(["get_views partner", "web_read partner"]);
await click(target, ".o_boolean_toggle");
- assert.verifySteps([
- "onchange2 turtle",
- "onchange2 partner",
- "write turtle",
- "web_read turtle",
- ]);
+ assert.verifySteps(["onchange2 partner", "write turtle", "web_read turtle"]);
});
QUnit.test("create a new record with an x2m invisible", async function (assert) {
diff --git a/addons/web/static/tests/views/kanban/kanban_view_tests.js b/addons/web/static/tests/views/kanban/kanban_view_tests.js
index bb9b6eecea6..8eb61142545 100644
--- a/addons/web/static/tests/views/kanban/kanban_view_tests.js
+++ b/addons/web/static/tests/views/kanban/kanban_view_tests.js
@@ -15,7 +15,6 @@ import {
mouseEnter,
nextTick,
patchWithCleanup,
- selectDropdownItem,
triggerEvent,
triggerHotkey,
} from "@web/../tests/helpers/utils";
@@ -5432,11 +5431,7 @@ QUnit.module("Views", (hooks) => {
}
);
- QUnit.test("prevent drag and drop of record if onchange fails", async (assert) => {
- serverData.models.partner.onchanges = {
- product_id() {},
- };
-
+ QUnit.test("prevent drag and drop of record if save fails", async (assert) => {
await makeView({
type: "kanban",
resModel: "partner",
@@ -5453,7 +5448,7 @@ QUnit.module("Views", (hooks) => {
"",
groupBy: ["product_id"],
async mockRPC(route, { model, method }) {
- if (model === "partner" && method === "onchange2") {
+ if (model === "partner" && method === "write") {
return Promise.reject({});
}
},
@@ -9928,14 +9923,17 @@ QUnit.module("Views", (hooks) => {
"unity_web_search_read",
"unity_web_search_read",
"write",
+ "web_read",
"read_progress_bar",
"/web/dataset/resequence",
"read",
"write",
+ "web_read",
"read_progress_bar",
"/web/dataset/resequence",
"read",
"write",
+ "web_read",
"read_progress_bar",
"/web/dataset/resequence",
"read",
@@ -9996,6 +9994,7 @@ QUnit.module("Views", (hooks) => {
"unity_web_search_read",
"unity_web_search_read",
"write",
+ "web_read",
"read_progress_bar",
"web_read_group",
"/web/dataset/resequence",
@@ -10077,6 +10076,7 @@ QUnit.module("Views", (hooks) => {
"unity_web_search_read",
"unity_web_search_read",
"write",
+ "web_read",
"read_progress_bar",
"/web/dataset/resequence",
"read",
@@ -11544,6 +11544,7 @@ QUnit.module("Views", (hooks) => {
"unity_web_search_read",
"unity_web_search_read",
"write",
+ "web_read",
"read_progress_bar",
"/web/dataset/resequence",
"read",
@@ -11629,6 +11630,7 @@ QUnit.module("Views", (hooks) => {
assert.deepEqual(getCardTexts(1), ["2blip", "3gnap"]);
assert.verifySteps([
"write",
+ "web_read",
"read_progress_bar",
"unity_web_search_read",
"/web/dataset/resequence",
@@ -12841,97 +12843,6 @@ QUnit.module("Views", (hooks) => {
assert.verifySteps(["resequence"]);
});
- QUnit.test("dragged record cannot be saved", async (assert) => {
- let def;
- serverData.models.partner.records = [
- { id: 1, bar: false, state: "abc" },
- { id: 2, bar: true, state: "def", foo: "blip" },
- ];
- serverData.models.partner.onchanges = {
- bar() {},
- };
-
- const kanban = await makeView({
- type: "kanban",
- resModel: "partner",
- serverData,
- arch: `
-