[IMP] move fetching of fields for import to javascript. Also extraction of required fields
bzr revid: xmo@openerp.com-20110923083341-xa3sg2t053zonlsm
This commit is contained in:
parent
6bd754060e
commit
baf367d0e1
|
@ -19,6 +19,7 @@
|
|||
"static/lib/jquery.ui/js/jquery-ui-1.8.9.custom.min.js",
|
||||
"static/lib/jquery.ui/js/jquery-ui-timepicker-addon.js",
|
||||
"static/lib/jquery.ui.notify/js/jquery.notify.js",
|
||||
"static/lib/jquery.deferred-queue/jquery.deferred-queue.js",
|
||||
"static/lib/json/json2.js",
|
||||
"static/lib/qweb/qweb2.js",
|
||||
"static/lib/underscore/underscore.js",
|
||||
|
|
|
@ -1428,9 +1428,6 @@ class Import(View):
|
|||
fields = req.session.model(model).fields_get(False, req.session.eval_context(req.context))
|
||||
fields.update({'id': {'string': 'ID'}, '.id': {'string': 'Database ID'}})
|
||||
|
||||
required_fields = [field_name for field_name, field in fields.iteritems()
|
||||
if field.get('required')]
|
||||
|
||||
def model_populate(fields, prefix_node='', prefix=None, prefix_value='', level=2):
|
||||
def str_comp(x,y):
|
||||
if x<y: return 1
|
||||
|
@ -1459,9 +1456,6 @@ class Import(View):
|
|||
fields.update({'id':{'string':'ID'},'.id':{'string':'Database ID'}})
|
||||
model_populate(fields)
|
||||
|
||||
all_fields = _fields.keys()
|
||||
all_fields.sort()
|
||||
|
||||
try:
|
||||
data = csv.reader(csvfile, quotechar=str(csvdel), delimiter=str(csvsep))
|
||||
except:
|
||||
|
@ -1504,8 +1498,7 @@ class Import(View):
|
|||
|
||||
return '<script>window.top.%s(%s);</script>' % (
|
||||
jsonp, simplejson.dumps({
|
||||
'records':records[1:],'header':header_fields,
|
||||
'all_fields':all_fields,'required_fields':required_fields}))
|
||||
'records':records[1:],'header':header_fields}))
|
||||
|
||||
@openerpweb.httprequest
|
||||
def import_data(self, req, model, csvfile, csvsep, csvdel, csvcode, csvskip,
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
Copyright 2011 Xavier Morel. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are
|
||||
permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
of conditions and the following disclaimer in the documentation and/or other materials
|
||||
provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY XAVIER MOREL ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,59 @@
|
|||
.. -*- restructuredtext -*-
|
||||
|
||||
In jQuery 1.5, jQuery has introduced a Deferred object in order to
|
||||
better handle callbacks.
|
||||
|
||||
Along with Deferred, it introduced ``jQuery.when`` which allows, among
|
||||
other things, for multiplexing deferreds (waiting on multiple
|
||||
deferreds at the same time).
|
||||
|
||||
While this is very nice if all deferreds are available at the same
|
||||
point, it doesn't really work if the resolution of a deferred can
|
||||
generate more deferreds, or for collections of deferreds coming from
|
||||
multiple sources (which may not be aware of one another).
|
||||
|
||||
Deferred.queue tries to be a solution to this. It is based on the
|
||||
principle of FIFO multiple-producers multiple-consumers tasks queues,
|
||||
such as Python's `queue.Queue`_. Any code with a reference to the
|
||||
queue can add a promise to the queue, and the queue (which is a
|
||||
promise itself) will only be resolved once all promises within are
|
||||
resolved.
|
||||
|
||||
Quickstart
|
||||
----------
|
||||
|
||||
Deferred.queue has a very simple life cycle: it is dormant when
|
||||
created, it starts working as soon as promises get added to it (via
|
||||
``.push``, or by providing them directly to its constructor), and as
|
||||
soon as the last promise in the queue is resolved it resolves itself.
|
||||
|
||||
If any promise in the queue fails, the queue itself will be rejected
|
||||
(without waiting for further promises).
|
||||
|
||||
Once a queue has been resolved or rejected, adding new promises to it
|
||||
results in an error.
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
``jQuery.Deferred.queue([promises...])``
|
||||
Creates a new deferred queue. Can be primed with a series of promise
|
||||
objects.
|
||||
|
||||
``.push(promise...)``
|
||||
Adds promises to the queue. Returns the queue itself (can be
|
||||
chained).
|
||||
|
||||
If the queue has already been resolved or rejected, raises an error.
|
||||
|
||||
``.then([doneCallbacks][, failCallbacks])``
|
||||
Promise/A ``then`` method.
|
||||
|
||||
``.done(doneCallbacks)``
|
||||
jQuery ``done`` extension to promise objects
|
||||
|
||||
``.fail(failCallbacks)``
|
||||
jQuery ``fail`` extension to promise objects
|
||||
|
||||
.. _queue.Queue:
|
||||
http://docs.python.org/dev/library/queue.html
|
|
@ -0,0 +1,34 @@
|
|||
(function ($) {
|
||||
"use strict";
|
||||
$.extend($.Deferred, {
|
||||
queue: function () {
|
||||
var queueDeferred = $.Deferred();
|
||||
var promises = 0;
|
||||
|
||||
function resolve() {
|
||||
if (--promises > 0) {
|
||||
return;
|
||||
}
|
||||
setTimeout($.proxy(queueDeferred, 'resolve'), 0);
|
||||
}
|
||||
|
||||
var promise = $.extend(queueDeferred.promise(), {
|
||||
push: function () {
|
||||
if (this.isResolved() || this.isRejected()) {
|
||||
throw new Error("Can not add promises to a resolved "
|
||||
+ "or rejected promise queue");
|
||||
}
|
||||
|
||||
promises += 1;
|
||||
$.when.apply(null, arguments).then(
|
||||
resolve, $.proxy(queueDeferred, 'reject'));
|
||||
return this;
|
||||
}
|
||||
});
|
||||
if (arguments.length) {
|
||||
promise.push.apply(promise, arguments);
|
||||
}
|
||||
return promise;
|
||||
}
|
||||
});
|
||||
})(jQuery)
|
|
@ -23,11 +23,36 @@ function jsonp(form, attributes, callback) {
|
|||
data: options
|
||||
}, attributes));
|
||||
}
|
||||
|
||||
openerp.web.DataImport = openerp.web.Dialog.extend({
|
||||
template: 'ImportDataView',
|
||||
dialog_title: "Import Data",
|
||||
init: function(parent, dataset){
|
||||
var self = this;
|
||||
this._super(parent, {});
|
||||
this.model = parent.model;
|
||||
this.fields = [];
|
||||
this.all_fields = [];
|
||||
this.required_fields;
|
||||
|
||||
var convert_fields = function (root, prefix) {
|
||||
prefix = prefix || '';
|
||||
_(root.fields).each(function (f) {
|
||||
var name = prefix + f.name;
|
||||
self.all_fields.push(name);
|
||||
if (f.fields) {
|
||||
convert_fields(f, name + '/');
|
||||
}
|
||||
});
|
||||
};
|
||||
this.ready = $.Deferred.queue().then(function () {
|
||||
self.required_fields = _(self.fields).chain()
|
||||
.filter(function (field) { return field.required; })
|
||||
.pluck('name')
|
||||
.value();
|
||||
convert_fields(self);
|
||||
self.all_fields.sort();
|
||||
});
|
||||
},
|
||||
start: function() {
|
||||
var self = this;
|
||||
|
@ -51,6 +76,35 @@ openerp.web.DataImport = openerp.web.Dialog.extend({
|
|||
this.$element.find('fieldset legend').click(function() {
|
||||
$(this).next().toggle();
|
||||
});
|
||||
this.ready.push(new openerp.web.DataSet(this, this.model).call(
|
||||
'fields_get', [], function (fields) {
|
||||
self.graft_fields(fields);
|
||||
}));
|
||||
},
|
||||
graft_fields: function (fields, parent, level) {
|
||||
parent = parent || this;
|
||||
level = level || 0;
|
||||
|
||||
var self = this;
|
||||
_(fields).each(function (field, field_name) {
|
||||
var f = {
|
||||
name: field_name,
|
||||
string: field.string,
|
||||
required: field.required
|
||||
};
|
||||
|
||||
if (field.type === 'one2many') {
|
||||
f.fields = [];
|
||||
// only fetch sub-fields to a depth of 2 levels
|
||||
if (level < 2) {
|
||||
self.ready.push(new openerp.web.DataSet(self, field.relation).call(
|
||||
'fields_get', [], function (fields) {
|
||||
self.graft_fields(fields, f, level+1);
|
||||
}));
|
||||
}
|
||||
}
|
||||
parent.fields.push(f);
|
||||
});
|
||||
},
|
||||
toggle_import_button: function (newstate) {
|
||||
this.$dialog.dialog('widget')
|
||||
|
@ -89,15 +143,13 @@ openerp.web.DataImport = openerp.web.Dialog.extend({
|
|||
var self = this;
|
||||
this.$element.find('.sel_fields').autocomplete({
|
||||
minLength: 0,
|
||||
source: results.all_fields,
|
||||
change: function () {
|
||||
self.on_check_field_values(results['required_fields']);
|
||||
}
|
||||
source: this.all_fields,
|
||||
change: self.on_check_field_values
|
||||
}).focus(function () {
|
||||
$(this).autocomplete('search');
|
||||
});
|
||||
|
||||
this.on_check_field_values(results['required_fields']);
|
||||
this.on_check_field_values();
|
||||
},
|
||||
/**
|
||||
* Looks through all the field selections, and tries to find if two
|
||||
|
@ -134,10 +186,10 @@ openerp.web.DataImport = openerp.web.Dialog.extend({
|
|||
});
|
||||
return duplicates;
|
||||
},
|
||||
on_check_field_values: function (required_fields) {
|
||||
on_check_field_values: function () {
|
||||
this.$element.find("#message, #msg").remove();
|
||||
|
||||
var required_valid = this.check_required(required_fields);
|
||||
var required_valid = this.check_required();
|
||||
|
||||
var duplicates = this.find_duplicate_fields();
|
||||
if (_.isEmpty(duplicates)) {
|
||||
|
@ -156,15 +208,15 @@ openerp.web.DataImport = openerp.web.Dialog.extend({
|
|||
}
|
||||
|
||||
},
|
||||
check_required: function(required_fields) {
|
||||
if (!required_fields.length) { return true; }
|
||||
check_required: function() {
|
||||
if (!this.required_fields.length) { return true; }
|
||||
|
||||
var selected_fields = _(this.$element.find('.sel_fields').get()).chain()
|
||||
.pluck('value')
|
||||
.compact()
|
||||
.value();
|
||||
|
||||
var missing_fields = _.difference(required_fields, selected_fields);
|
||||
var missing_fields = _.difference(this.required_fields, selected_fields);
|
||||
if (missing_fields.length) {
|
||||
this.$element.find("#result").before('<div id="message" style="color:red">*Required Fields are not selected : ' + missing_fields + '.</div>');
|
||||
return false;
|
||||
|
|
Loading…
Reference in New Issue