diff --git a/addons/base/controllers/main.py b/addons/base/controllers/main.py index 0684964256f..3b8ed588169 100644 --- a/addons/base/controllers/main.py +++ b/addons/base/controllers/main.py @@ -170,25 +170,7 @@ class Session(openerpweb.Controller): a list of fields to group by, potentially empty (in which case no group by should be performed) """ - context = req.session.eval_contexts(contexts) - domain = req.session.eval_domains(domains, context) - - group_by_sequence = [] - for candidate in (group_by_seq or []): - ctx = req.session.eval_context(candidate, context) - group_by = ctx.get('group_by') - if not group_by: - continue - elif isinstance(group_by, basestring): - group_by_sequence.append(group_by) - else: - group_by_sequence.extend(group_by) - - return { - 'context': context, - 'domain': domain, - 'group_by': group_by_sequence - } + return _eval_domain_and_context(req, contexts, domains, group_by_seq) @openerpweb.jsonrequest def save_session_action(self, req, the_action): @@ -230,6 +212,26 @@ class Session(openerpweb.Controller): return None return saved_actions["actions"].get(key) +def _eval_domain_and_context(req, contexts, domains, group_by_seq=None): + context = req.session.eval_contexts(contexts) + domain = req.session.eval_domains(domains, context) + + group_by_sequence = [] + for candidate in (group_by_seq or []): + ctx = req.session.eval_context(candidate, context) + group_by = ctx.get('group_by') + if not group_by: + continue + elif isinstance(group_by, basestring): + group_by_sequence.append(group_by) + else: + group_by_sequence.extend(group_by) + + return { + 'context': context, + 'domain': domain, + 'group_by': group_by_sequence + } def load_actions_from_ir_values(req, key, key2, models, meta, context): Values = req.session.model('ir.values') @@ -434,7 +436,15 @@ class DataSet(openerpweb.Controller): return Model.unlink(ids) @openerpweb.jsonrequest - def call(self, req, model, method, args): + def call(self, req, model, method, args, domain_id=None, context_id=None): + domain = args[domain_id] if domain_id and len(args) - 1 >= domain_id else [] + context = args[context_id] if context_id and len(args) - 1 >= context_id else {} + res = _eval_domain_and_context(req, [context], [domain]); + if(domain_id and len(args) - 1 >= domain_id): + args[context_id] = res["context"] + if(context_id and len(args) - 1 >= context_id): + args[domain_id] = res["domain"] + m = req.session.model(model) r = getattr(m, method)(*args) return {'result': r} diff --git a/addons/base/static/src/js/data.js b/addons/base/static/src/js/data.js index 76a803fa0ff..581bd217ba9 100644 --- a/addons/base/static/src/js/data.js +++ b/addons/base/static/src/js/data.js @@ -320,13 +320,22 @@ openerp.base.DataSet = openerp.base.Controller.extend( /** @lends openerp.base. args: args || [] }, callback, error_callback); }, + call_and_eval: function (method, args, domain_id, context_id, callback, error_callback) { + return this.rpc('/base/dataset/call', { + model: this.model, + method: method, + domain_id: domain_id || null, + context_id: context_id || null, + args: args || [] + }, callback, error_callback); + }, /** * Arguments: * name='', args=[], operator='ilike', context=None, limit=100 */ name_search: function (args, callback, error_callback) { - return this.call('name_search', - args, + return this.call_and_eval('name_search', + args, 1, 3, callback, error_callback); }, exec_workflow: function (id, signal, callback) { @@ -431,6 +440,36 @@ openerp.base.DataSetSearch = openerp.base.DataSet.extend({ } }); +openerp.base.CompoundContext = function(source_context) { + this.__ref = "compound_context"; + this.__contexts = []; + if (source_context === undefined) + return; + else if (source_context.__ref === "compound_context") + this.__contexts.concat(source_context.__contexts); + else + this.add(source_context); +}; +openerp.base.CompoundContext.prototype.add = function(context) { + this.__contexts.push(context); + return this; +}; + +openerp.base.CompoundDomain = function(source_domain) { + this.__ref = "compound_domain"; + this.__domains = []; + if (source_domain === undefined) + return; + else if (source_domain.__ref === "compound_domain") + this.__domains.concat(source_domain.__domains); + else + this.add(source_domain); +}; +openerp.base.CompoundDomain.prototype.add = function(domain) { + this.__domains.push(domain); + return this; +}; + }; // vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax: diff --git a/addons/base/static/src/js/form.js b/addons/base/static/src/js/form.js index 8269e9a0cd6..2aa29fac377 100644 --- a/addons/base/static/src/js/form.js +++ b/addons/base/static/src/js/form.js @@ -1013,6 +1013,18 @@ openerp.base.form.FieldSelection = openerp.base.form.Field.extend({ }); })(null); +/** + * Builds a new context usable for operations related to fields by merging + * the fields'context with the action's context. + */ +var build_relation_context = function(relation_field) { + var action = relation_field.view.view_manager.action || {}; + var a_context = action.context || {}; + var f_context = relation_field.field.context || {}; + var ctx = new openerp.base.CompoundContext(a_context).add(f_context); + return ctx; +} + openerp.base.form.FieldMany2One = openerp.base.form.Field.extend({ init: function(view, node) { this._super(view, node); @@ -1048,7 +1060,8 @@ openerp.base.form.FieldMany2One = openerp.base.form.Field.extend({ "type":"ir.actions.act_window", "view_type":"form", "view_mode":"form", - "target":"new" + "target":"new", + "context": build_relation_context(self) }); }; var cmenu = this.$menu_btn.contextMenu(this.cm_id, {'leftClickToo': true, @@ -1125,23 +1138,26 @@ openerp.base.form.FieldMany2One = openerp.base.form.Field.extend({ var dataset = new openerp.base.DataSetStatic(this.session, this.field.relation, []); - dataset.name_search([search_val, [], 'ilike', {}, this.limit + 1], function(data) { + dataset.name_search([search_val, self.field.domain || [], 'ilike', + build_relation_context(self), this.limit + 1], function(data) { self.last_search = data.result; // possible selections for the m2o var values = _.map(data.result, function(x) { return {label: $('').text(x[1]).html(), name:x[1], id:x[0]}; }); - // additional selections, actions that open popup + // search more... if more results that max if (values.length > self.limit) { values = values.slice(0, self.limit); values.push({label: "   Search More...", action: function() { - dataset.name_search([search_val, [], 'ilike', {}, false], function(data) { + dataset.name_search([search_val, self.field.domain || [], 'ilike', + build_relation_context(self), false], function(data) { self._change_int_value(null); self._search_create_popup("search", data.result); }); }}); } + // quick create var raw_result = _(data.result).map(function(x) {return x[1];}) if (search_val.length > 0 && !_.include(raw_result, search_val) && @@ -1151,6 +1167,7 @@ openerp.base.form.FieldMany2One = openerp.base.form.Field.extend({ self._quick_create(search_val); }}); } + // create... values.push({label: "   Create and Edit...", action: function() { self._change_int_value(null); self._search_create_popup("form"); @@ -1162,7 +1179,7 @@ openerp.base.form.FieldMany2One = openerp.base.form.Field.extend({ _quick_create: function(name) { var self = this; var dataset = new openerp.base.DataSetStatic(this.session, this.field.relation, []); - dataset.call("name_create", [name, {}], function(data) { + dataset.call("name_create", [name, build_relation_context(self)], function(data) { self._change_int_ext_value(data.result); }, function(a, b) { self._change_int_value(null); @@ -1401,8 +1418,10 @@ openerp.base.form.SelectCreatePopup = openerp.base.BaseWidget.extend({ * - disable_multiple_selection * - alternative_form_view */ - select_element: function(model, options) { + select_element: function(model, options, domain, context) { this.model = model; + this.domain = domain || []; + this.context = context || {}; this.options = options || {}; this.initial_ids = this.options.initial_ids; jQuery(this.render()).dialog({title: '', @@ -1485,7 +1504,6 @@ openerp.base.form.SelectCreatePopup = openerp.base.BaseWidget.extend({ this.view_form = new openerp.base.FormView(null, this.session, this.element_id + "_view_form", this.dataset, false); if (this.options.alternative_form_view) { - debugger; this.view_form.set_embedded_view(this.options.alternative_form_view); } this.view_form.start(); diff --git a/openerpweb/nonliterals.py b/openerpweb/nonliterals.py index 1584628f777..38c94e6d230 100644 --- a/openerpweb/nonliterals.py +++ b/openerpweb/nonliterals.py @@ -27,6 +27,16 @@ class NonLiteralEncoder(simplejson.encoder.JSONEncoder): '__ref': 'context', '__id': object.key } + elif isinstance(object, CompoundDomain): + return { + '__ref': 'compound_domain', + '__domains': [self.default(el) for el in object.domains] + } + elif isinstance(object, CompoundContext): + return { + '__ref': 'compound_context', + '__contexts': [self.default(el) for el in object.contexts] + } return super(NonLiteralEncoder, self).default(object) def non_literal_decoder(dct): @@ -47,6 +57,16 @@ def non_literal_decoder(dct): if 'own_values' in dct: context.own = dct['own_values'] return context + elif dct["__ref"] == "compound_domain": + cdomain = CompoundDomain() + for el in dct["__domains"]: + cdomain.domains.append(non_literal_decoder(el)) + return cdomain + elif dct["__ref"] == "compound_context": + ccontext = CompoundContext() + for el in dct["__contexts"]: + ccontext.contexts.append(non_literal_decoder(el)) + return ccontext return dct class Domain(object): @@ -138,3 +158,59 @@ class Context(object): ctx.update(self.own) return eval(self.get_context_string(), ctx) + +class CompoundDomain: + def __init__(self): + self.domains = [] + self.session = None + + def evaluate(self, context=None): + final_domain = [] + for domain in self.domains: + if not isinstance(domain, (list, Domain, CompoundDomain)): + raise TypeError("Domain %r is not a list or a nonliteral Domain", + domain) + + if isinstance(domain, list): + final_domain.extend(domain) + break + + ctx = dict(context or {}) + ctx['context'] = ctx + + domain.session = self.session + domain.extend(domain.evaluate(ctx)) + return final_domain + + def add(self, domain): + self.domains.append(domain) + return self + +class CompoundContext: + def __init__(self): + self.contexts = [] + self.session = None + + def evaluate(self, context=None): + ctx = dict(context or {}) + final_context = {} + for context_to_eval in self.contexts: + if not isinstance(context_to_eval, (dict, Context, CompoundContext)): + raise TypeError("Context %r is not a dict or a nonliteral Context", + context_to_eval) + + if isinstance(context_to_eval, dict): + final_context.update(context_to_eval) + break + + ctx.update(final_context) + ctx["context"] = ctx + + context_to_eval.session = self.session + final_context.update(context_to_eval.evaluate(ctx)) + return final_context + + def add(self, context): + self.contexts.append(context) + return self + diff --git a/openerpweb/openerpweb.py b/openerpweb/openerpweb.py index 5ef4369dbb5..2ee59779cb3 100644 --- a/openerpweb/openerpweb.py +++ b/openerpweb/openerpweb.py @@ -194,7 +194,7 @@ class OpenERPSession(object): :raises: ``TypeError`` if ``context_to_eval`` is neither a dict nor a Context """ - if not isinstance(context_to_eval, (dict, nonliterals.Domain)): + if not isinstance(context_to_eval, (dict, nonliterals.Context, nonliterals.CompoundContext)): raise TypeError("Context %r is not a dict or a nonliteral Context", context_to_eval) @@ -250,7 +250,7 @@ class OpenERPSession(object): :raises: ``TypeError`` if ``domain`` is neither a list nor a Domain """ - if not isinstance(domain, (list, nonliterals.Domain)): + if not isinstance(domain, (list, nonliterals.Domain, nonliterals.CompoundDomain)): raise TypeError("Domain %r is not a list or a nonliteral Domain", domain)