Merge lp:~gkliska/server-env-tools/server-env-tools-61 into lp:~server-env-tools-core-editors/server-env-tools/6.1

Proposed by Goran Kliska
Status: Needs review
Proposed branch: lp:~gkliska/server-env-tools/server-env-tools-61
Merge into: lp:~server-env-tools-core-editors/server-env-tools/6.1
Diff against target: 303 lines (+284/-0)
3 files modified
web_base/__init__.py (+22/-0)
web_base/__openerp__.py (+69/-0)
web_base/static/src/js/view_form_base.js (+193/-0)
To merge this branch: bzr merge lp:~gkliska/server-env-tools/server-env-tools-61
Reviewer Review Type Date Requested Status
Pedro Manuel Baeza Abstain
Review via email: mp+204699@code.launchpad.net

Description of the change

New web module for 6.1 web client.
1.Fixing wishlist: Fields with attribute readonly=True do not preserve on_change values
         https://bugs.launchpad.net/openerp-web/+bug/378824 Reported by Ferdinand on 2009-05-20
         If field is (readonly and required and dirty) then it is "readonly_writable". 3 LOC
2.Allowing parent.field for in attrs
         Example: <field name="amount" attrs="{'readonly':[('*parent.*entry_type','!=','amount')],'required':[('*parent.*entry_type','!=','amount')]}"/>

To post a comment you must log in.
Revision history for this message
Pedro Manuel Baeza (pedro.baeza) wrote :

Don't you think this is better as a bugfix in OCB branch?

Regards.

review: Needs Information
Revision history for this message
Goran Kliska (gkliska) wrote :

@Pedro
Yes,
but I did it in a few hours using Chrome debugger (first time with OpenERP) and patching web client directly.
This is my first web module and I wrote it without basic knowledge about OE web client.
Results of my tests are: 1. It is not throwing errors, 2. It's working on my test case (one2many form view),
but I don't know will it produce some unwanted side effects.
After all, this "wishlist" is from 2009 - for sure it must be more than 3LOC patch.

IMO My proposal needs review from someone with deeper understanding of web client before it can be considered OCB quality.
I am puzzled in L:193 with how deep this.view.widget_parent.widget_parent.... must go to reliably find parent data set.

In my TODO list regarding this is:
  1. Make attrs="{'readonly':[('product_id.uom_alternatives','!=',True)]} possible.
     I don't know (yet) how to prefill fields with something like this this.view.fields[product_id][uom_alternatives]
  2. Duplicate this funcionality for v8

I didn't know that OCB is mandatory for OCA modules.
All I know - No more dummy fields in my modules.

BRGDS

Revision history for this message
Pedro Manuel Baeza (pedro.baeza) wrote :

OK then, I let then the review to someone with JS skills (it's one of my pendings).

Regards.

review: Abstain
Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

> I didn't know that OCB is mandatory for OCA modules.

They shouldn't require OCB. If you see incompatibilities in modules with the OpenERP branches (not OCB), please report them as bugs.

Regarding your proposal, I can't help.

Unmerged revisions

44. By Slobodni programi

New module web_base

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory 'web_base'
2=== added file 'web_base/__init__.py'
3--- web_base/__init__.py 1970-01-01 00:00:00 +0000
4+++ web_base/__init__.py 2014-02-04 14:41:41 +0000
5@@ -0,0 +1,22 @@
6+# -*- coding: utf-8 -*-
7+##############################################################################
8+#
9+# OpenERP, Open Source Management Solution
10+# Copyright (C) 2014 Decodio ERP/Slobodni Programi d.o.o. (<http://slobodni-programi.com>).
11+#
12+# This program is free software: you can redistribute it and/or modify
13+# it under the terms of the GNU Affero General Public License as
14+# published by the Free Software Foundation, either version 3 of the
15+# License, or (at your option) any later version.
16+#
17+# This program is distributed in the hope that it will be useful,
18+# but WITHOUT ANY WARRANTY; without even the implied warranty of
19+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20+# GNU Affero General Public License for more details.
21+#
22+# You should have received a copy of the GNU Affero General Public License
23+# along with this program. If not, see <http://www.gnu.org/licenses/>.
24+#
25+##############################################################################
26+
27+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
28
29=== added file 'web_base/__openerp__.py'
30--- web_base/__openerp__.py 1970-01-01 00:00:00 +0000
31+++ web_base/__openerp__.py 2014-02-04 14:41:41 +0000
32@@ -0,0 +1,69 @@
33+# -*- coding: utf-8 -*-
34+##############################################################################
35+#
36+# OpenERP, Open Source Management Solution
37+# Copyright (C) 2014 Decodio / Slobodni Programi d.o.o. (<http://slobodni-programi.com>).
38+# Author: Goran Kliska
39+#
40+# This program is free software: you can redistribute it and/or modify
41+# it under the terms of the GNU Affero General Public License as
42+# published by the Free Software Foundation, either version 3 of the
43+# License, or (at your option) any later version.
44+#
45+# This program is distributed in the hope that it will be useful,
46+# but WITHOUT ANY WARRANTY; without even the implied warranty of
47+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
48+# GNU Affero General Public License for more details.
49+#
50+# You should have received a copy of the GNU Affero General Public License
51+# along with this program. If not, see <http://www.gnu.org/licenses/>.
52+#
53+##############################################################################
54+
55+
56+{
57+ 'name': 'Web Base',
58+ 'version': '6.3.1.0',
59+ 'category': 'Borg/Base',
60+ 'complexity': "normal",
61+ "depends": [
62+ # 'base_base',
63+ 'web',
64+ ],
65+ "js": [
66+ 'static/src/js/view_form_base.js',
67+ # 'static/src/js/view_list_base.js',
68+ ],
69+ 'qweb': [
70+ # 'static/xml/*.xml',
71+ ],
72+ 'css': [
73+ # 'static/css/*.css',
74+ ],
75+ 'author': 'Decodio - Slobodni programi d.o.o.',
76+ 'website': 'http://slobodni-programi.com',
77+ 'installable' : True,
78+ 'active' : False,
79+ # 'auto_install': True,
80+ 'description':
81+ """
82+ 1. Fixing Wishlist: Fields with attribute readonly=True do not preserve on_change values
83+ https://bugs.launchpad.net/openerp-web/+bug/378824 Reported by Ferdinand on 2009-05-20
84+ If field is (readonly and required and dirty) then it is "readonly_writable". 3 LOC
85+ Example:
86+ <field name="uom_id" on_change="onchange_product_uom( ...
87+ <field name="base_uom_qty" readonly="1" required="1"/>
88+ Method onchange_product_uom(...) is calculating and changing value of
89+ "base_uom_qty" field and making it "dirty".
90+ Field is readonly and required and it will be saved in the client dataset
91+ and sent to orm create and write methods.
92+ It is good practice to recalculate all important fields again in create and write methods.
93+
94+ 2. Allowing parent.field for in attrs
95+ Example: <field name="amount" attrs="{'readonly':[('parent.entry_type','!=','amount')],'required':[('parent.entry_type','!=','amount')]}"/>
96+ """,
97+ 'data': [],
98+ 'demo_xml': [],
99+ 'images': [],
100+}
101+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
102
103=== added directory 'web_base/static'
104=== added directory 'web_base/static/src'
105=== added directory 'web_base/static/src/js'
106=== added file 'web_base/static/src/js/view_form_base.js'
107--- web_base/static/src/js/view_form_base.js 1970-01-01 00:00:00 +0000
108+++ web_base/static/src/js/view_form_base.js 2014-02-04 14:41:41 +0000
109@@ -0,0 +1,193 @@
110+openerp.web_base = function(openerp) {
111+var QWeb = openerp.web.qweb,
112+ _t = openerp.web._t,
113+ _lt = openerp.web._lt;
114+
115+openerp.web.form.Field = openerp.web.form.Field.extend({
116+
117+ is_dirty: function() {
118+ // DECODIO KGB START Save readony required dirty
119+ //return this.dirty && !this.readonly;
120+ return this.dirty && ( !this.readonly || (this.required && this.readonly));
121+ }
122+});
123+
124+
125+openerp.web.FormView = openerp.web.FormView.extend({
126+ do_save: function(success, prepend_on_create) {
127+ var self = this;
128+ return this.mutating_mutex.exec(function() { return self.is_initialized.pipe(function() {
129+ try {
130+ var form_invalid = false,
131+ values = {},
132+ first_invalid_field = null;
133+ for (var f in self.fields) {
134+ f = self.fields[f];
135+ if (!f.is_valid()) {
136+ form_invalid = true;
137+ if (!first_invalid_field) {
138+ first_invalid_field = f;
139+ }
140+ } else if (f.name !== 'id' && !f.readonly && (!self.datarecord.id || f.is_dirty())) {
141+ // Special case 'id' field, do not save this field
142+ // on 'create' : save all non readonly fields
143+ // on 'edit' : save non readonly modified fields
144+ values[f.name] = f.get_value();
145+ // DECODIO KGB START Save readony required dirty
146+ } else if (f.name !== 'id' && f.readonly && f.required && f.is_dirty()) {
147+ values[f.name] = f.get_value();
148+ // DECODIO KGB END Save readony required dirty
149+ }
150+ f.update_dom(true);
151+ }
152+ if (form_invalid) {
153+ first_invalid_field.focus();
154+ self.on_invalid();
155+ return $.Deferred().reject();
156+ } else {
157+ var save_deferral;
158+ if (!self.datarecord.id) {
159+ //console.log("FormView(", self, ") : About to create", values);
160+ save_deferral = self.dataset.create(values).pipe(function(r) {
161+ return self.on_created(r, undefined, prepend_on_create);
162+ }, null);
163+ } else if (_.isEmpty(values) && ! self.force_dirty) {
164+ //console.log("FormView(", self, ") : Nothing to save");
165+ save_deferral = $.Deferred().resolve({}).promise();
166+ } else {
167+ self.force_dirty = false;
168+ //console.log("FormView(", self, ") : About to save", values);
169+ save_deferral = self.dataset.write(self.datarecord.id, values, {}).pipe(function(r) {
170+ return self.on_saved(r);
171+ }, null);
172+ }
173+ return save_deferral.then(success);
174+ }
175+ } catch (e) {
176+ console.error(e);
177+ return $.Deferred().reject();
178+ }
179+ });});
180+ },
181+
182+});
183+
184+openerp.web.form.Widget = openerp.web.form.Widget.extend({
185+
186+ process_modifiers: function() {
187+ var compute_domain = openerp.web.form.compute_domain;
188+ /** DECODIO START KGB allow parent.field in attribs */
189+ // trying to find (guesswork) parent fields values
190+ var parent_fields;
191+ var i=0;
192+ tmp_parent = this.view.widget_parent;
193+ while (i<10) {
194+ if (tmp_parent && tmp_parent.model){
195+ if (tmp_parent.model !== this.view.model) {
196+ parent_fields = tmp_parent.fields;
197+ break;
198+ }
199+ }
200+ if (tmp_parent.widget_parent){
201+ tmp_parent = tmp_parent.widget_parent;
202+ } else {
203+ parent_fields = false;
204+ break;
205+ }
206+ i++;
207+ }
208+ for (var a in this.modifiers) {
209+ //this[a] = compute_domain(this.modifiers[a], this.view.fields);
210+ this[a] = compute_domain(this.modifiers[a], this.view.fields, parent_fields);
211+ }
212+ }
213+});
214+
215+
216+/** DECODIO KGB allow parent.field in attribs */
217+openerp.web.form.compute_domain = function(expr, fields, parent_fields) {
218+ var stack = [];
219+ for (var i = expr.length - 1; i >= 0; i--) {
220+ var ex = expr[i];
221+ if (ex.length == 1) {
222+ var top = stack.pop();
223+ switch (ex) {
224+ case '|':
225+ stack.push(stack.pop() || top);
226+ continue;
227+ case '&':
228+ stack.push(stack.pop() && top);
229+ continue;
230+ case '!':
231+ stack.push(!top);
232+ continue;
233+ default:
234+ throw new Error(_.str.sprintf(
235+ _t("Unknown operator %s in domain %s"),
236+ ex, JSON.stringify(expr)));
237+ }
238+ }
239+
240+ var field = fields[ex[0]];
241+ /** DECODIO START KGB allow parent.field in attribs */
242+ var parent_field;
243+ var splitted;
244+ if (parent_fields && !field ) {
245+ splitted = ex[0].split('.');
246+ if (splitted.length > 1 && splitted[0] === "parent") {
247+ parent_field = parent_fields[splitted[1]];
248+ }
249+ }
250+ if ((!field) && (!parent_field)) {
251+ throw new Error(_.str.sprintf(
252+ _t("Unknown field %s in domain %s"),
253+ ex[0], JSON.stringify(expr)));
254+ }
255+ if (field) {
256+ var field_value = field.get_value ? fields[ex[0]].get_value() : fields[ex[0]].value;
257+ }
258+ if (parent_field) {
259+ var field_value = parent_field.get_value ? parent_fields[splitted[1]].get_value() : parent_fields[splitted[1]].value;
260+ }
261+ /** DECODIO END KGB allow parent.field in attribs */
262+ var op = ex[1];
263+ var val = ex[2];
264+
265+ switch (op.toLowerCase()) {
266+ case '=':
267+ case '==':
268+ stack.push(field_value == val);
269+ break;
270+ case '!=':
271+ case '<>':
272+ stack.push(field_value != val);
273+ break;
274+ case '<':
275+ stack.push(field_value < val);
276+ break;
277+ case '>':
278+ stack.push(field_value > val);
279+ break;
280+ case '<=':
281+ stack.push(field_value <= val);
282+ break;
283+ case '>=':
284+ stack.push(field_value >= val);
285+ break;
286+ case 'in':
287+ if (!_.isArray(val)) val = [val];
288+ stack.push(_(val).contains(field_value));
289+ break;
290+ case 'not in':
291+ if (!_.isArray(val)) val = [val];
292+ stack.push(!_(val).contains(field_value));
293+ break;
294+ default:
295+ console.warn(
296+ _t("Unsupported operator %s in domain %s"),
297+ op, JSON.stringify(expr));
298+ }
299+ }
300+ return _.all(stack, _.identity);
301+};
302+};
303\ No newline at end of file

Subscribers

People subscribed via source and target branches