Browse Source

Merge pull request #743 from simahawk/mig-10-web_readonly_bypass

[MIG][10.0] web_readonly_bypass
pull/763/head
Pedro M. Baeza 7 years ago
committed by GitHub
parent
commit
edcbae383b
  1. 15
      web_readonly_bypass/README.rst
  2. 32
      web_readonly_bypass/__manifest__.py
  3. 73
      web_readonly_bypass/static/src/js/readonly_bypass.js
  4. 328
      web_readonly_bypass/static/test/web_readonly_bypass.js
  5. 1
      web_readonly_bypass/tests/__init__.py
  6. 15
      web_readonly_bypass/tests/test_ui.py
  7. 27
      web_readonly_bypass/views/readonly_bypass.xml

15
web_readonly_bypass/README.rst

@ -22,7 +22,7 @@ This module changes the behaviour of Odoo by propagating
on_change modifications to readonly fields to the backend create and write on_change modifications to readonly fields to the backend create and write
methods. methods.
To change that behavior you have to set context on ``ur.actions.act_window``::
To change that behavior you have to set context on ``ir.actions.act_window``::
<record id="sale.action_quotations" model="ir.actions.act_window"> <record id="sale.action_quotations" model="ir.actions.act_window">
<field name="context">{'readonly_by_pass': True}</field> <field name="context">{'readonly_by_pass': True}</field>
@ -36,13 +36,13 @@ or by telling fields allowed to change::
</field> </field>
</record> </record>
For further information, please visit:
On one2many fields, you can also pass the context in the field definition:
* https://www.odoo.com/forum/help-1
<field name="one2many_field" context="{'readonly_by_pass': True}"/>
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas .. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
:alt: Try me on Runbot :alt: Try me on Runbot
:target: https://runbot.odoo-community.org/runbot/162/8.0
:target: https://runbot.odoo-community.org/runbot/162/10.0
Bug Tracker Bug Tracker
@ -50,8 +50,7 @@ Bug Tracker
Bugs are tracked on `GitHub Issues <https://github.com/OCA/web/issues>`_. 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. 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
`here <https://github.com/OCA/web/issues/new?body=module:%20web_readonly_bypass%0Aversion:%208.0.1.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
If you spotted it first, help us smashing it by providing a detailed and welcomed feedback.
Credits Credits
@ -63,6 +62,10 @@ Contributors
* Jonathan Nemry <jonathan.nemry@acsone.eu> * Jonathan Nemry <jonathan.nemry@acsone.eu>
* Laetitia Gangloff <laetitia.gangloff@acsone.eu> * Laetitia Gangloff <laetitia.gangloff@acsone.eu>
* Pierre Verkest <pverkest@anybox.fr> * Pierre Verkest <pverkest@anybox.fr>
* Kalpana Hemnani <hemnani.kalpana@gmail.com>
* Agathe Mollé <agathe.molle@savoirfairelinux.com>
* Simone Orsi <simone.orsi@camptocamp.com>
Maintainer Maintainer
---------- ----------

32
web_readonly_bypass/__manifest__.py

@ -1,33 +1,13 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
##############################################################################
#
# This file is part of web_readonly_bypass,
# an Odoo module.
#
# Copyright (c) 2015 ACSONE SA/NV (<http://acsone.eu>)
#
# web_readonly_bypass is free software:
# you can redistribute it and/or modify it under the terms of the GNU
# Affero General Public License as published by the Free Software
# Foundation,either version 3 of the License, or (at your option) any
# later version.
#
# web_readonly_bypass is distributed
# in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
# PURPOSE. See the GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with web_readonly_bypass.
# If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
# Copyright (c) 2015 ACSONE SA/NV (<http://acsone.eu>)
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
{ {
'name': 'Read Only ByPass', 'name': 'Read Only ByPass',
'version': '9.0.1.0.0',
'version': '10.0.1.0.1',
"author": "ACSONE SA/NV, Odoo Community Association (OCA)", "author": "ACSONE SA/NV, Odoo Community Association (OCA)",
"maintainer": "ACSONE SA/NV,Odoo Community Association (OCA)",
"website": "http://www.acsone.eu", "website": "http://www.acsone.eu",
"license": "LGPL-3",
'category': 'Technical Settings', 'category': 'Technical Settings',
'depends': [ 'depends': [
'web', 'web',
@ -36,6 +16,6 @@
'data': [ 'data': [
'views/readonly_bypass.xml', 'views/readonly_bypass.xml',
], ],
'installable': False,
'installable': True,
'auto_install': False, 'auto_install': False,
} }

73
web_readonly_bypass/static/src/js/readonly_bypass.js

@ -1,9 +1,10 @@
"use strict";
(function(){
var instance = openerp;
var QWeb = instance.web.qweb, _t = instance.web._t;
odoo.define('web_readonly_bypass', function(require) {
'use strict';
instance.web_readonly_bypass = {
var data = require('web.data'),
pyeval = require('web.pyeval');
var readonly_bypass = {
/** /**
* ignore readonly: place options['readonly_fields'] into the data * ignore readonly: place options['readonly_fields'] into the data
* if nothing is specified into the context * if nothing is specified into the context
@ -26,7 +27,7 @@
} }
}); });
} }
data = $.extend(data,readonly_by_pass_fields);
data = $.extend(data, readonly_by_pass_fields);
}, },
/** /**
@ -59,15 +60,13 @@
}, },
}; };
var readonly_bypass = instance.web_readonly_bypass;
instance.web.BufferedDataSet.include({
data.BufferedDataSet.include({
init : function() { init : function() {
this._super.apply(this, arguments); this._super.apply(this, arguments);
}, },
/** /**
* Creates Overriding
* Create Overriding
* *
* @param {Object} data field values to set on the new record * @param {Object} data field values to set on the new record
* @param {Object} options Dictionary that can contain the following keys: * @param {Object} options Dictionary that can contain the following keys:
@ -77,13 +76,12 @@
*/ */
create : function(data, options) { create : function(data, options) {
var self = this; var self = this;
var context = instance.web.pyeval.eval('contexts',
self.context.__eval_context);
var context = pyeval.eval('contexts', self.context.get_eval_context());
readonly_bypass.ignore_readonly(data, options, true, context); readonly_bypass.ignore_readonly(data, options, true, context);
return self._super(data,options); return self._super(data,options);
}, },
/** /**
* Creates Overriding
* Write Overriding
* *
* @param {Object} data field values to set on the new record * @param {Object} data field values to set on the new record
* @param {Object} options Dictionary that can contain the following keys: * @param {Object} options Dictionary that can contain the following keys:
@ -93,15 +91,14 @@
*/ */
write : function(id, data, options) { write : function(id, data, options) {
var self = this; var self = this;
var context = instance.web.pyeval.eval('contexts',
self.context.__eval_context);
var context = pyeval.eval('contexts', self.context.get_eval_context());
readonly_bypass.ignore_readonly(data, options, false, context); readonly_bypass.ignore_readonly(data, options, false, context);
return self._super(id,data,options); return self._super(id,data,options);
}, },
}); });
instance.web.DataSet.include({
data.DataSet.include({
/* /*
BufferedDataSet: case of 'add an item' into a form view BufferedDataSet: case of 'add an item' into a form view
*/ */
@ -138,4 +135,46 @@
}, },
}); });
})();
data.ProxyDataSet.include({
/*
ProxyDataSet: case of 'pop-up'
*/
init : function() {
this._super.apply(this, arguments);
},
/**
* Create Overriding
*
* @param {Object} data field values to set on the new record
* @param {Object} options Dictionary that can contain the following keys:
* - readonly_fields: Values from readonly fields that were updated by
* on_changes. Only used by the BufferedDataSet to make the o2m work correctly.
* @returns super {$.Deferred}
*/
create : function(data, options) {
var self = this;
var context = pyeval.eval('contexts', self.context.get_eval_context());
readonly_bypass.ignore_readonly(data, options, true, context);
return self._super(data,options);
},
/**
* Write Overriding
*
* @param {Object} data field values to set on the new record
* @param {Object} options Dictionary that can contain the following keys:
* - readonly_fields: Values from readonly fields that were updated by
* on_changes. Only used by the BufferedDataSet to make the o2m work correctly.
* @returns super {$.Deferred}
*/
write : function(id, data, options) {
var self = this;
var context = pyeval.eval('contexts', self.context.get_eval_context());
readonly_bypass.ignore_readonly(data, options, false, context);
return self._super(id,data,options);
},
});
return readonly_bypass;
});

328
web_readonly_bypass/static/test/web_readonly_bypass.js

@ -1,166 +1,166 @@
openerp.testing.section( 'web_readonly_bypass', {},
function(test){
test('ignore_readonly', function(instance){
var data = {};
var mode_create = true;
var options = {};
var context = {};
instance.web_readonly_bypass.ignore_readonly(data, options,
mode_create, context);
deepEqual(data,
{},
"Empty context and options mode create"
);
mode_create = false;
data = {};
instance.web_readonly_bypass.ignore_readonly(data, options,
mode_create, context);
deepEqual(data,
{},
"Empty context and options mode write"
);
mode_create = false;
data = {};
context = {'readonly_by_pass': true};
options = {'readonly_fields': {'field_1': 'va1-1',
'field_2': false,
odoo.define_section('web_readonly_bypass', ['web_readonly_bypass'], function(test) {
"use strict";
test('ignore_readonly', function(assert, ro_bypass){
var data = {};
var mode_create = true;
var options = {};
var context = {};
ro_bypass.ignore_readonly(data, options, mode_create, context);
assert.deepEqual(data,
{},
"Empty context and options mode create"
);
mode_create = false;
data = {};
ro_bypass.ignore_readonly(data, options, mode_create, context);
assert.deepEqual(data,
{},
"Empty context and options mode write"
);
mode_create = false;
data = {};
context = {'readonly_by_pass': true};
options = {'readonly_fields': {'field_1': 'va1-1',
'field_2': false,
'field_3': 'val-3'}};
ro_bypass.ignore_readonly(data, options, mode_create, context);
assert.deepEqual(data,
{'field_1': 'va1-1', 'field_2': false, 'field_3': 'val-3'},
"all fields mode write"
);
mode_create = true;
data = {};
context = {'readonly_by_pass': true};
options = {'readonly_fields': {'field_1': 'va1-1',
'field_2': false,
'field_3': 'val-3'}};
ro_bypass.ignore_readonly(data, options, mode_create, context);
assert.deepEqual(data,
{'field_1': 'va1-1', 'field_3': 'val-3'},
"all fields mode create (false value are escaped)"
);
mode_create = true;
data = {};
context = {};
options = {'readonly_fields': {'field_1': 'va1-1',
'field_2': false,
'field_3': 'val-3'}};
ro_bypass.ignore_readonly(data, options, mode_create, context);
assert.deepEqual(data,
{},
"without context, default, we won't save readonly fields"
);
});
test('retrieve_readonly_by_pass_fields', ['web_readonly_bypass'], function(assert, ro_bypass){
var context = {'readonly_by_pass': true}
var options = {'readonly_fields': {'field_1': 'va1-1',
'field_2': 'val-2',
'field_3': 'val-3'}}; 'field_3': 'val-3'}};
instance.web_readonly_bypass.ignore_readonly(data, options,
mode_create, context);
deepEqual(data,
{'field_1': 'va1-1', 'field_2': false, 'field_3': 'val-3'},
"all fields mode write"
);
mode_create = true;
data = {};
context = {'readonly_by_pass': true};
options = {'readonly_fields': {'field_1': 'va1-1',
'field_2': false,
'field_3': 'val-3'}};
instance.web_readonly_bypass.ignore_readonly(data, options,
mode_create, context);
deepEqual(data,
{'field_1': 'va1-1', 'field_3': 'val-3'},
"all fields mode create (false value are escaped)"
);
mode_create = true;
data = {};
context = {};
options = {'readonly_fields': {'field_1': 'va1-1',
'field_2': false,
'field_3': 'val-3'}};
instance.web_readonly_bypass.ignore_readonly(data, options,
mode_create, context);
deepEqual(data,
{},
"without context, default, we won't save readonly fields"
);
});
test('retrieve_readonly_by_pass_fields', function(instance){
var context = {'readonly_by_pass': true}
var options = {'readonly_fields': {'field_1': 'va1-1',
'field_2': 'val-2',
'field_3': 'val-3'}};
deepEqual(
instance.web_readonly_bypass.retrieve_readonly_by_pass_fields(
options, context),
{'field_1': 'va1-1', 'field_2': 'val-2', 'field_3': 'val-3'},
"All fields should be accepted!"
);
context = {'readonly_by_pass': ['field_1', 'field_3']};
deepEqual(
instance.web_readonly_bypass.retrieve_readonly_by_pass_fields(
options, context),
{'field_1': 'va1-1','field_3': 'val-3'},
"two field s1"
);
context = {'readonly_by_pass': ['field_1',]};
deepEqual(
instance.web_readonly_bypass.retrieve_readonly_by_pass_fields(
options, context),
{'field_1': 'va1-1'},
"Only field 1"
);
context = {'readonly_by_pass': []};
deepEqual(
instance.web_readonly_bypass.retrieve_readonly_by_pass_fields(
options, context),
{},
"Empty context field"
);
context = null;
deepEqual(
instance.web_readonly_bypass.retrieve_readonly_by_pass_fields(
options, context),
{},
"Null context"
);
context = false;
deepEqual(
instance.web_readonly_bypass.retrieve_readonly_by_pass_fields(
options, context),
{},
"false context"
);
context = {'readonly_by_pass': true}
options = {'readonly_fields': {'field_1': 'va1-1'}};
deepEqual(
instance.web_readonly_bypass.retrieve_readonly_by_pass_fields(
options, context),
{'field_1': 'va1-1'},
"Only one option"
);
options = {'readonly_fields': {}};
deepEqual(
instance.web_readonly_bypass.retrieve_readonly_by_pass_fields(
options, context),
{},
"Empty readonly_fields option"
);
options = {};
deepEqual(
instance.web_readonly_bypass.retrieve_readonly_by_pass_fields(
options, context),
{},
"Empty option"
);
options = null;
deepEqual(
instance.web_readonly_bypass.retrieve_readonly_by_pass_fields(
options, context),
{},
"null option"
);
options = false;
deepEqual(
instance.web_readonly_bypass.retrieve_readonly_by_pass_fields(
options, context),
{},
"false option"
);
context = false;
deepEqual(
instance.web_readonly_bypass.retrieve_readonly_by_pass_fields(
options, context),
{},
"false option and false context"
);
});
assert.deepEqual(
ro_bypass.retrieve_readonly_by_pass_fields(
options, context),
{'field_1': 'va1-1', 'field_2': 'val-2', 'field_3': 'val-3'},
"All fields should be accepted!"
);
context = {'readonly_by_pass': ['field_1', 'field_3']};
assert.deepEqual(
ro_bypass.retrieve_readonly_by_pass_fields(
options, context),
{'field_1': 'va1-1','field_3': 'val-3'},
"two field s1"
);
context = {'readonly_by_pass': ['field_1',]};
assert.deepEqual(
ro_bypass.retrieve_readonly_by_pass_fields(
options, context),
{'field_1': 'va1-1'},
"Only field 1"
);
context = {'readonly_by_pass': []};
assert.deepEqual(
ro_bypass.retrieve_readonly_by_pass_fields(
options, context),
{},
"Empty context field"
);
context = null;
assert.deepEqual(
ro_bypass.retrieve_readonly_by_pass_fields(
options, context),
{},
"Null context"
);
context = false;
assert.deepEqual(
ro_bypass.retrieve_readonly_by_pass_fields(
options, context),
{},
"false context"
);
context = {'readonly_by_pass': true}
options = {'readonly_fields': {'field_1': 'va1-1'}};
assert.deepEqual(
ro_bypass.retrieve_readonly_by_pass_fields(
options, context),
{'field_1': 'va1-1'},
"Only one option"
);
options = {'readonly_fields': {}};
assert.deepEqual(
ro_bypass.retrieve_readonly_by_pass_fields(
options, context),
{},
"Empty readonly_fields option"
);
options = {};
assert.deepEqual(
ro_bypass.retrieve_readonly_by_pass_fields(
options, context),
{},
"Empty option"
);
options = null;
assert.deepEqual(
ro_bypass.retrieve_readonly_by_pass_fields(
options, context),
{},
"null option"
);
options = false;
assert.deepEqual(
ro_bypass.retrieve_readonly_by_pass_fields(
options, context),
{},
"false option"
);
context = false;
assert.deepEqual(
ro_bypass.retrieve_readonly_by_pass_fields(
options, context),
{},
"false option and false context"
);
});
}); });

1
web_readonly_bypass/tests/__init__.py

@ -0,0 +1 @@
from . import test_ui

15
web_readonly_bypass/tests/test_ui.py

@ -0,0 +1,15 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2017 Simone Orsi <simone.orsi@camptocamp.com>
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
from odoo.tests import HttpCase
class TestUi(HttpCase):
def test_ui_web(self):
self.phantom_js(
"/web/tests?module=web_readonly_bypass",
"",
login="admin",
)

27
web_readonly_bypass/views/readonly_bypass.xml

@ -1,15 +1,14 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<template id="assets_backend" name="web_readonly_bypass" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<script type="text/javascript" src="/web_readonly_bypass/static/src/js/readonly_bypass.js"></script>
</xpath>
</template>
<template id="qunit_suite" name="web_readonly_bypass" inherit_id="web.qunit_suite">
<xpath expr="//head" position="inside">
<script type="text/javascript" src="/web_readonly_bypass/static/test/web_readonly_bypass.js"></script>
</xpath>
</template>
</data>
</openerp>
<odoo>
<template id="assets_backend" name="web_readonly_bypass" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<script type="text/javascript" src="/web_readonly_bypass/static/src/js/readonly_bypass.js"></script>
</xpath>
</template>
<template id="qunit_suite" name="web_readonly_bypass" inherit_id="web.qunit_suite">
<xpath expr="//t[@t-set='head']" position="inside">
<script type="text/javascript" src="/web_readonly_bypass/static/test/web_readonly_bypass.js"></script>
</xpath>
</template>
</odoo>
Loading…
Cancel
Save