diff --git a/addons/web/static/src/js/views/basic/basic_model.js b/addons/web/static/src/js/views/basic/basic_model.js index ced26fb7cb2..304f7e475f7 100644 --- a/addons/web/static/src/js/views/basic/basic_model.js +++ b/addons/web/static/src/js/views/basic/basic_model.js @@ -612,6 +612,15 @@ var BasicModel = AbstractModel.extend({ // make sure we don't write an undefined id delete changes.id; + // remove readonly fields from the list of changes + if (method === 'write') { + for (var fieldName in changes) { + if (record.fields[fieldName].readonly) { + delete changes[fieldName]; + } + } + } + // in the case of a write, only perform the RPC if there are changes to save if (method === 'create' || Object.keys(changes).length) { var args = method === 'write' ? [[record.data.id], changes] : [changes]; diff --git a/addons/web/static/test/views/basic_model_tests.js b/addons/web/static/test/views/basic_model_tests.js index cda5e044e08..026a9d18c0f 100644 --- a/addons/web/static/test/views/basic_model_tests.js +++ b/addons/web/static/test/views/basic_model_tests.js @@ -983,4 +983,64 @@ QUnit.module('Views', { }); model.destroy(); }); + + QUnit.test('dont write on readonly fields (except if create)', function (assert) { + assert.expect(6); + + this.params.fieldNames = ['foo', 'bar']; + this.data.partner.onchanges.foo = function (obj) { + obj.bar = obj.foo.length; + }; + this.data.partner.fields.bar.readonly = true; + + var model = createModel({ + Model: BasicModel, + data: this.data, + mockRPC: function (route, args) { + if (args.method === 'write') { + assert.deepEqual(args.args[1], {foo: "verylongstring"}, + "should only save foo field"); + } + if (args.method === 'create') { + assert.deepEqual(args.args[0], { + foo: "anotherverylongstring", + bar: 21, + }, "should also save bar field in create mode"); + } + return this._super(route, args); + }, + }); + + model.load(this.params).then(function (resultID) { + var record = model.get(resultID); + assert.strictEqual(record.data.bar, 2, + "should be initialized with correct value"); + + model.notifyChanges(resultID, {foo: "verylongstring"}); + + record = model.get(resultID); + assert.strictEqual(record.data.bar, 14, + "should be changed with correct value"); + + model.save(resultID); + }); + + // start again, but with a new record + delete this.params.res_id; + model.load(this.params).then(function (resultID) { + var record = model.get(resultID); + assert.strictEqual(record.data.bar, false, + "should be initialized with correct value"); + + model.notifyChanges(resultID, {foo: "anotherverylongstring"}); + + record = model.get(resultID); + assert.strictEqual(record.data.bar, 21, + "should be changed with correct value"); + + model.save(resultID); + }); + model.destroy(); + }); + });});