From 627bb128e04991fad61688b8b86ca82061a90977 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Wed, 26 Sep 2012 10:25:30 +0200 Subject: [PATCH 01/50] [IMP] adapt base_import to using Model.load instead of Model.import_data bzr revid: xmo@openerp.com-20120926082530-krhladsrn9mzs3lx --- addons/base_import/models.py | 30 ++++++------------------------ 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/addons/base_import/models.py b/addons/base_import/models.py index 1e5ad002b84..733532ae095 100644 --- a/addons/base_import/models.py +++ b/addons/base_import/models.py @@ -307,22 +307,14 @@ class ir_import(orm.TransientModel): except ValueError, e: return [{ 'type': 'error', - 'message': str(e), + 'message': unicode(e), 'record': False, }] - try: - _logger.info('importing %d rows...', len(data)) - (code, record, message, _wat) = self.pool[record.res_model].import_data( - cr, uid, import_fields, data, context=context) - _logger.info('done') - - except Exception, e: - _logger.exception("Import failed") - # TODO: remove when exceptions stop being an "expected" - # behavior of import_data on some (most) invalid - # input. - code, record, message = -1, None, str(e) + _logger.info('importing %d rows...', len(data)) + import_result = self.pool[record.res_model].load( + cr, uid, import_fields, data, context=context) + _logger.info('done') # If transaction aborted, RELEASE SAVEPOINT is going to raise # an InternalError (ROLLBACK should work, maybe). Ignore that. @@ -339,14 +331,4 @@ class ir_import(orm.TransientModel): except psycopg2.InternalError: pass - if code != -1: - return [] - - # TODO: add key for error location? - # TODO: error not within normal preview, how to display? Re-preview - # with higher ``count``? - return [{ - 'type': 'error', - 'message': message, - 'record': record or False - }] + return import_result['messages'] From fd5d4e5dd34eeeec885ffd2fe5ae340c5bebb00c Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Wed, 26 Sep 2012 13:42:35 +0200 Subject: [PATCH 02/50] [IMP] don't display deprecated fields in import window bzr revid: xmo@openerp.com-20120926114235-iqkmi23yk2v1hq7w --- addons/base_import/models.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/addons/base_import/models.py b/addons/base_import/models.py index 733532ae095..16bb52d5856 100644 --- a/addons/base_import/models.py +++ b/addons/base_import/models.py @@ -83,6 +83,10 @@ class ir_import(orm.TransientModel): }] fields_got = self.pool[model].fields_get(cr, uid, context=context) for name, field in fields_got.iteritems(): + # an empty string means the field is deprecated, @deprecated must + # be absent or False to mean not-deprecated + if field.get('deprecated', False) is not False: + continue if field.get('readonly'): states = field.get('states') if not states: @@ -97,7 +101,7 @@ class ir_import(orm.TransientModel): 'id': name, 'name': name, 'string': field['string'], - # Y U NO ALWAYS HAVE REQUIRED + # Y U NO ALWAYS HAS REQUIRED 'required': bool(field.get('required')), 'fields': [], } From f6f37632ceb0ed2a6abd043c884e5e9de1cb8d51 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Wed, 26 Sep 2012 15:50:13 +0200 Subject: [PATCH 03/50] [IMP] errors display, dryrun management (add button) bzr revid: xmo@openerp.com-20120926135013-rkbvxluu6tqz9a1l --- addons/base_import/static/src/js/import.js | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/addons/base_import/static/src/js/import.js b/addons/base_import/static/src/js/import.js index c2deb660ff2..9cb2f74bd48 100644 --- a/addons/base_import/static/src/js/import.js +++ b/addons/base_import/static/src/js/import.js @@ -63,7 +63,7 @@ openerp.base_import = function (instance) { {name: 'quoting', label: _lt("Quoting:"), value: '"'} ], events: { - 'change .oe_import_grid input': 'import_dryrun', + // 'change .oe_import_grid input': 'import_dryrun', 'change input.oe_import_file': 'file_update', 'change input.oe_import_has_header, .oe_import_options input': 'settings_updated', 'click a.oe_import_csv': function (e) { @@ -85,9 +85,10 @@ openerp.base_import = function (instance) { var self = this; this._super(parent, { buttons: [ - {text: _t("Import File"), click: function () { - self.do_import(); - }, 'class': 'oe_import_dialog_button'} + {text: _t("Import"), click: self.proxy('do_import'), + 'class': 'oe_import_dialog_button'}, + {text: _t("Validate"), click: self.proxy('import_dryrun'), + 'class': 'oe_import_dialog_button'} ] }); this.res_model = parent.model; @@ -134,11 +135,12 @@ openerp.base_import = function (instance) { .then(this.proxy('preview')); }, preview: function (result) { + this.$el.removeClass('oe_import_preview_error oe_import_error'); this.$el.toggleClass( 'oe_import_noheaders', !this.$('input.oe_import_has_header').prop('checked')); if (result.error) { - this.$el.addClass('oe_import_error'); + this.$el.addClass('oe_import_preview_error oe_import_error'); this.$('.oe_import_error_report').html( QWeb.render('ImportView.preview.error', result)); return; @@ -180,7 +182,7 @@ openerp.base_import = function (instance) { width: 'resolve', dropdownCssClass: 'oe_import_selector' }); - this.import_dryrun(); + //this.import_dryrun(); }, generate_fields_completion: function (root) { var basic = []; @@ -252,7 +254,6 @@ openerp.base_import = function (instance) { //- import itself call_import: function (options) { - var self = this; var fields = this.$('.oe_import_fields input.oe_import_match_field').map(function (index, el) { return $(el).select2('val') || false; }).get(); @@ -260,12 +261,12 @@ openerp.base_import = function (instance) { 'do', [this.id, fields, this.import_options()], options); }, import_dryrun: function () { -// this.call_import({ dryrun: true }) -// .then(this.proxy('render_import_errors')); + return this.call_import({ dryrun: true }) + .then(this.proxy('render_import_errors')); }, do_import: function () { var self = this; - this.call_import({ dryrun: false }).then(function (errors) { + return this.call_import({ dryrun: false }).then(function (errors) { if (_.isEmpty(errors)) { if (self.getParent().reload_content) { self.getParent().reload_content(); From 27aeae974aa4a001e7c8f13cd01f98a5ca295334 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Wed, 26 Sep 2012 18:50:52 +0200 Subject: [PATCH 04/50] [IMP] warning and error reporting during import bzr revid: xmo@openerp.com-20120926165052-7eq4ne62h63zbqqm --- addons/base_import/static/src/css/import.css | 6 ++- addons/base_import/static/src/js/import.js | 41 +++++++++++++++----- addons/base_import/static/src/xml/import.xml | 26 +++++++++++-- 3 files changed, 58 insertions(+), 15 deletions(-) diff --git a/addons/base_import/static/src/css/import.css b/addons/base_import/static/src/css/import.css index f6258f5aa50..da61473fdba 100644 --- a/addons/base_import/static/src/css/import.css +++ b/addons/base_import/static/src/css/import.css @@ -10,7 +10,8 @@ .oe_import .oe_import_grid, .oe_import .oe_import_error_report, .oe_import .oe_import_with_file, -.oe_import .oe_import_noheaders { +.oe_import .oe_import_noheaders, +.oe_import .oe_import_report_more { display: none; } @@ -19,7 +20,8 @@ } .oe_import.oe_import_error .oe_import_error_report, .oe_import.oe_import_with_file .oe_import_with_file, -.oe_import.oe_import_noheaders .oe_import_noheaders { +.oe_import.oe_import_noheaders .oe_import_noheaders, +.oe_import .oe_import_report_showmore .oe_import_report_more { display: block; } diff --git a/addons/base_import/static/src/js/import.js b/addons/base_import/static/src/js/import.js index 9cb2f74bd48..d5f059d0656 100644 --- a/addons/base_import/static/src/js/import.js +++ b/addons/base_import/static/src/js/import.js @@ -79,6 +79,10 @@ openerp.base_import = function (instance) { ? $el.next() : $el.parent().next()) .toggle(); + }, + 'click .oe_import_report a.oe_import_report_count': function (e) { + e.preventDefault(); + $(e.target).parent().toggleClass('oe_import_report_showmore'); } }, init: function (parent, dataset) { @@ -262,31 +266,50 @@ openerp.base_import = function (instance) { }, import_dryrun: function () { return this.call_import({ dryrun: true }) - .then(this.proxy('render_import_errors')); + .then(this.proxy('render_import_result')); }, do_import: function () { var self = this; - return this.call_import({ dryrun: false }).then(function (errors) { - if (_.isEmpty(errors)) { + return this.call_import({ dryrun: false }).then(function (message) { + if (!_.any(message, function (message) { + return message.type === 'error' })) { if (self.getParent().reload_content) { self.getParent().reload_content(); } self.close(); return; } - self.render_import_errors(errors); + self.render_import_result(message); }); }, - render_import_errors: function (errors) { - if (_.isEmpty(errors)) { + render_import_result: function (message) { + if (_.isEmpty(message)) { this.$el.removeClass('oe_import_error'); return; } - // import failed (or maybe just warnings, if we ever get - // warnings?) + // row indexes come back 0-indexed, spreadsheets + // display 1-indexed. + var offset = 1; + // offset more if header + if (this.import_options().header) { offset += 1; } + this.$el.addClass('oe_import_error'); this.$('.oe_import_error_report').html( - QWeb.render('ImportView.error', {errors: errors})); + QWeb.render('ImportView.error', { + errors: _(message).groupBy('message'), + at: function (rows) { + var from = rows.from + offset; + var to = rows.to + offset; + if (from === to) { + return _.str.sprintf(_t("at row %d"), from); + } + return _.str.sprintf(_t("between rows %d and %d"), + from, to); + }, + more: function (n) { + return _.str.sprintf(_t("(%d times more)"), n); + }, + })); }, }); }; diff --git a/addons/base_import/static/src/xml/import.xml b/addons/base_import/static/src/xml/import.xml index 386348bea4b..5d36eae4d2d 100644 --- a/addons/base_import/static/src/xml/import.xml +++ b/addons/base_import/static/src/xml/import.xml @@ -86,12 +86,30 @@
    -
  • - - +
  • + + + + + + + +
      +
    • + + + +
    • +
+ + + + + + this.attr('t-if', 'widget.options.import_enabled'); From 4d7576393a3e0efadf639dbe9958725f76ae6f10 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Thu, 27 Sep 2012 09:48:45 +0200 Subject: [PATCH 05/50] [ADD] unstyled and incomplete handling of @moreinfo action triggering is still missing bzr revid: xmo@openerp.com-20120927074845-pb3osgymmtddglc0 --- addons/base_import/static/src/js/import.js | 35 +++++++++++++++++++- addons/base_import/static/src/xml/import.xml | 3 +- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/addons/base_import/static/src/js/import.js b/addons/base_import/static/src/js/import.js index d5f059d0656..ac81f89c7a9 100644 --- a/addons/base_import/static/src/js/import.js +++ b/addons/base_import/static/src/js/import.js @@ -83,6 +83,12 @@ openerp.base_import = function (instance) { 'click .oe_import_report a.oe_import_report_count': function (e) { e.preventDefault(); $(e.target).parent().toggleClass('oe_import_report_showmore'); + }, + 'click .oe_import_moreinfo_action a': function (e) { + e.preventDefault(); + // #data will parse the attribute on its own, we don't like that + var action = JSON.parse($(e.target).attr('data-action')); + console.log(action); } }, init: function (parent, dataset) { @@ -307,7 +313,34 @@ openerp.base_import = function (instance) { from, to); }, more: function (n) { - return _.str.sprintf(_t("(%d times more)"), n); + return _.str.sprintf(_t("(%d more)"), n); + }, + info: function (msg) { + if (typeof msg === 'string') { + return _.str.sprintf( + '
%s
', + _.str.escapeHTML(msg)); + } + if (msg instanceof Array) { + return _.str.sprintf( + '
%s
    %s
', + _.str.escapeHTML(_t("Here are the possible values:")), + _(msg).map(function (msg) { + return '
  • ' + + _.str.escapeHTML(msg) + + '
  • '; + }).join()); + } + // Final should be object, action descriptor + return [ + '' + ].join('') }, })); }, diff --git a/addons/base_import/static/src/xml/import.xml b/addons/base_import/static/src/xml/import.xml index 5d36eae4d2d..2efd0b5a752 100644 --- a/addons/base_import/static/src/xml/import.xml +++ b/addons/base_import/static/src/xml/import.xml @@ -108,7 +108,8 @@ - + + From 4787939773e175475c03d70c4e32fdf0eeea1097 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Thu, 27 Sep 2012 11:49:50 +0200 Subject: [PATCH 06/50] [FIX] correctly transform 'get all possible values' action links to display list views as list views bzr revid: xmo@openerp.com-20120927094950-pwlgv2kt2a0jz8ji --- addons/base_import/static/src/js/import.js | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/addons/base_import/static/src/js/import.js b/addons/base_import/static/src/js/import.js index ac81f89c7a9..8a73bcd5d71 100644 --- a/addons/base_import/static/src/js/import.js +++ b/addons/base_import/static/src/js/import.js @@ -86,9 +86,20 @@ openerp.base_import = function (instance) { }, 'click .oe_import_moreinfo_action a': function (e) { e.preventDefault(); - // #data will parse the attribute on its own, we don't like that + // #data will parse the attribute on its own, we don't like + // that sort of things var action = JSON.parse($(e.target).attr('data-action')); - console.log(action); + // FIXME: when JS-side clean_action + action.views = _(action.views).map(function (view) { + var id = view[0], type = view[1]; + return [ + id, + type !== 'tree' ? type + : action.view_type === 'form' ? 'list' + : 'tree' + ]; + }); + this.do_action(_.extend(action, {target: 'new'})); } }, init: function (parent, dataset) { @@ -329,7 +340,7 @@ openerp.base_import = function (instance) { return '
  • ' + _.str.escapeHTML(msg) + '
  • '; - }).join()); + }).join('')); } // Final should be object, action descriptor return [ From 45ee8b434d6ea9d1f1570478a091ce0eab2cc37d Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Mon, 1 Oct 2012 09:17:28 +0200 Subject: [PATCH 07/50] [FIX] account: incorrect check for parent_id value would try a read on parent_id=False, which blows up bzr revid: xmo@openerp.com-20121001071728-npq7ieoe3rpz44i7 --- addons/account/account.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/account/account.py b/addons/account/account.py index e5e29f178a3..4eb99dc4bd4 100644 --- a/addons/account/account.py +++ b/addons/account/account.py @@ -2522,14 +2522,14 @@ class account_account_template(osv.osv): ] def create(self, cr, uid, vals, context=None): - if 'parent_id' in vals: + if vals.get('parent_id'): parent = self.read(cr, uid, [vals['parent_id']], ['type']) if parent and parent[0]['type'] != 'view': raise osv.except_osv(_('Warning!'), _("You may only select a parent account of type 'View'.")) return super(account_account_template, self).create(cr, uid, vals, context=context) def write(self, cr, uid, ids, vals, context=None): - if 'parent_id' in vals: + if vals.get('parent_id'): parent = self.read(cr, uid, [vals['parent_id']], ['type']) if parent and parent[0]['type'] != 'view': raise osv.except_osv(_('Warning!'), _("You may only select a parent account of type 'View'.")) From 49998b5f72f2fa8a33472cc849203278cb80bbf0 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Mon, 1 Oct 2012 09:59:31 +0200 Subject: [PATCH 08/50] [FIX] account: correctly handle 'false' close_method bzr revid: xmo@openerp.com-20121001075931-zyrmydt1s7uz7ihk --- addons/account/account.py | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/account/account.py b/addons/account/account.py index 4eb99dc4bd4..878f8759239 100644 --- a/addons/account/account.py +++ b/addons/account/account.py @@ -155,6 +155,7 @@ class account_account_type(osv.osv): return res def _save_report_type(self, cr, uid, account_type_id, field_name, field_value, arg, context=None): + field_value = field_value or 'none' obj_data = self.pool.get('ir.model.data') obj_financial_report = self.pool.get('account.financial.report') #unlink if it exists somewhere in the financial reports related to BS or PL From abf0579a9825a1a72a7525b26c80c87838fd6058 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Mon, 1 Oct 2012 12:52:35 +0200 Subject: [PATCH 09/50] [IMP] Invert order of buttons in import dialog, add 'or cancel' link bzr revid: xmo@openerp.com-20121001105235-0d954cxt9y80q89w --- addons/base_import/static/src/js/import.js | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/addons/base_import/static/src/js/import.js b/addons/base_import/static/src/js/import.js index 8a73bcd5d71..2a7e6f18d8a 100644 --- a/addons/base_import/static/src/js/import.js +++ b/addons/base_import/static/src/js/import.js @@ -106,10 +106,10 @@ openerp.base_import = function (instance) { var self = this; this._super(parent, { buttons: [ - {text: _t("Import"), click: self.proxy('do_import'), - 'class': 'oe_import_dialog_button'}, {text: _t("Validate"), click: self.proxy('import_dryrun'), - 'class': 'oe_import_dialog_button'} + 'class': 'oe_import_dialog_button'}, + {text: _t("Import"), click: self.proxy('do_import'), + 'class': 'oe_import_dialog_button oe_highlight'} ] }); this.res_model = parent.model; @@ -126,6 +126,16 @@ openerp.base_import = function (instance) { self.$('input[name=import_id]').val(id); }); }, + open: function () { + this._super.apply(this, arguments); + this.$el.dialog('widget').find('.ui-dialog-buttonset') + .append(_t(" or ")) + .append( + $(' + + or + Cancel + From e8a7d276bf700b3c880d4e961cfac1ea0b40c690 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Wed, 3 Oct 2012 14:16:19 +0200 Subject: [PATCH 15/50] [IMP] highlight toggling between validation and import buttons bzr revid: xmo@openerp.com-20121003121619-e6nbd78mfa5owycp --- addons/base_import/static/src/js/import.js | 6 ++++-- addons/base_import/static/src/xml/import.xml | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/addons/base_import/static/src/js/import.js b/addons/base_import/static/src/js/import.js index dd8b3288de9..4135f303513 100644 --- a/addons/base_import/static/src/js/import.js +++ b/addons/base_import/static/src/js/import.js @@ -325,8 +325,10 @@ openerp.base_import = function (instance) { }); }, render_import_result: function (message) { - if (_.isEmpty(message)) { - this.$('.oe_import_import').addClass('oe_highlight'); + var no_messages = _.isEmpty(message); + this.$('.oe_import_import').toggleClass('oe_highlight', no_messages); + this.$('.oe_import_validate').toggleClass('oe_highlight', !no_messages); + if (no_messages) { message.push({ type: 'info', message: _t("Everything seems valid.") diff --git a/addons/base_import/static/src/xml/import.xml b/addons/base_import/static/src/xml/import.xml index aab9482ee81..b0eea1fcf75 100644 --- a/addons/base_import/static/src/xml/import.xml +++ b/addons/base_import/static/src/xml/import.xml @@ -4,7 +4,7 @@
    + + + + + +
    +
    + +
    + dashed lines are asynchronous state transitions (3 seconds) +
    + + + + + + + + + + + diff --git a/addons/base_import/static/lib/javascript-state-machine/state-machine.js b/addons/base_import/static/lib/javascript-state-machine/state-machine.js new file mode 100644 index 00000000000..0d503ee7bdb --- /dev/null +++ b/addons/base_import/static/lib/javascript-state-machine/state-machine.js @@ -0,0 +1,155 @@ +(function (window) { + + StateMachine = { + + //--------------------------------------------------------------------------- + + VERSION: "2.1.0", + + //--------------------------------------------------------------------------- + + Result: { + SUCCEEDED: 1, // the event transitioned successfully from one state to another + NOTRANSITION: 2, // the event was successfull but no state transition was necessary + CANCELLED: 3, // the event was cancelled by the caller in a beforeEvent callback + ASYNC: 4, // the event is asynchronous and the caller is in control of when the transition occurs + }, + + Error: { + INVALID_TRANSITION: 100, // caller tried to fire an event that was innapropriate in the current state + PENDING_TRANSITION: 200, // caller tried to fire an event while an async transition was still pending + INVALID_CALLBACK: 300, // caller provided callback function threw an exception + }, + + WILDCARD: '*', + ASYNC: 'async', + + //--------------------------------------------------------------------------- + + create: function(cfg, target) { + + var initial = (typeof cfg.initial == 'string') ? { state: cfg.initial } : cfg.initial; // allow for a simple string, or an object with { state: 'foo', event: 'setup', defer: true|false } + var fsm = target || cfg.target || {}; + var events = cfg.events || []; + var callbacks = cfg.callbacks || {}; + var map = {}; + + var add = function(e) { + var from = (e.from instanceof Array) ? e.from : (e.from ? [e.from] : [StateMachine.WILDCARD]); // allow 'wildcard' transition if 'from' is not specified + map[e.name] = map[e.name] || {}; + for (var n = 0 ; n < from.length ; n++) + map[e.name][from[n]] = e.to || from[n]; // allow no-op transition if 'to' is not specified + }; + + if (initial) { + initial.event = initial.event || 'startup'; + add({ name: initial.event, from: 'none', to: initial.state }); + } + + for(var n = 0 ; n < events.length ; n++) + add(events[n]); + + for(var name in map) { + if (map.hasOwnProperty(name)) + fsm[name] = StateMachine.buildEvent(name, map[name]); + } + + for(var name in callbacks) { + if (callbacks.hasOwnProperty(name)) + fsm[name] = callbacks[name] + } + + fsm.current = 'none'; + fsm.is = function(state) { return this.current == state; }; + fsm.can = function(event) { return !this.transition && (map[event].hasOwnProperty(this.current) || map[event].hasOwnProperty(StateMachine.WILDCARD)); } + fsm.cannot = function(event) { return !this.can(event); }; + fsm.error = cfg.error || function(name, from, to, args, error, msg) { throw msg; }; // default behavior when something unexpected happens is to throw an exception, but caller can override this behavior if desired (see github issue #3) + + if (initial && !initial.defer) + fsm[initial.event](); + + return fsm; + + }, + + //=========================================================================== + + doCallback: function(fsm, func, name, from, to, args) { + if (func) { + try { + return func.apply(fsm, [name, from, to].concat(args)); + } + catch(e) { + return fsm.error(name, from, to, args, StateMachine.Error.INVALID_CALLBACK, "an exception occurred in a caller-provided callback function"); + } + } + }, + + beforeEvent: function(fsm, name, from, to, args) { return StateMachine.doCallback(fsm, fsm['onbefore' + name], name, from, to, args); }, + afterEvent: function(fsm, name, from, to, args) { return StateMachine.doCallback(fsm, fsm['onafter' + name] || fsm['on' + name], name, from, to, args); }, + leaveState: function(fsm, name, from, to, args) { return StateMachine.doCallback(fsm, fsm['onleave' + from], name, from, to, args); }, + enterState: function(fsm, name, from, to, args) { return StateMachine.doCallback(fsm, fsm['onenter' + to] || fsm['on' + to], name, from, to, args); }, + changeState: function(fsm, name, from, to, args) { return StateMachine.doCallback(fsm, fsm['onchangestate'], name, from, to, args); }, + + + buildEvent: function(name, map) { + return function() { + + var from = this.current; + var to = map[from] || map[StateMachine.WILDCARD] || from; + var args = Array.prototype.slice.call(arguments); // turn arguments into pure array + + if (this.transition) + return this.error(name, from, to, args, StateMachine.Error.PENDING_TRANSITION, "event " + name + " inappropriate because previous transition did not complete"); + + if (this.cannot(name)) + return this.error(name, from, to, args, StateMachine.Error.INVALID_TRANSITION, "event " + name + " inappropriate in current state " + this.current); + + if (false === StateMachine.beforeEvent(this, name, from, to, args)) + return StateMachine.CANCELLED; + + if (from === to) { + StateMachine.afterEvent(this, name, from, to, args); + return StateMachine.NOTRANSITION; + } + + // prepare a transition method for use EITHER lower down, or by caller if they want an async transition (indicated by an ASYNC return value from leaveState) + var fsm = this; + this.transition = function() { + fsm.transition = null; // this method should only ever be called once + fsm.current = to; + StateMachine.enterState( fsm, name, from, to, args); + StateMachine.changeState(fsm, name, from, to, args); + StateMachine.afterEvent( fsm, name, from, to, args); + }; + + var leave = StateMachine.leaveState(this, name, from, to, args); + if (false === leave) { + this.transition = null; + return StateMachine.CANCELLED; + } + else if ("async" === leave) { + return StateMachine.ASYNC; + } + else { + if (this.transition) + this.transition(); // in case user manually called transition() but forgot to return ASYNC + return StateMachine.SUCCEEDED; + } + + }; + } + + }; // StateMachine + + //=========================================================================== + + if ("function" === typeof define) { + define("statemachine", [], function() { return StateMachine; }); + } + else { + window.StateMachine = StateMachine; + } + +}(this)); + diff --git a/addons/base_import/static/src/js/import.js b/addons/base_import/static/src/js/import.js index 4135f303513..19d4e466cc7 100644 --- a/addons/base_import/static/src/js/import.js +++ b/addons/base_import/static/src/js/import.js @@ -71,14 +71,8 @@ openerp.base_import = function (instance) { ], events: { // 'change .oe_import_grid input': 'import_dryrun', - 'change input.oe_import_file': 'file_update', - 'change input.oe_import_has_header, .oe_import_options input': 'settings_updated', - 'click a.oe_import_csv': function (e) { - e.preventDefault(); - }, - 'click a.oe_import_export': function (e) { - e.preventDefault(); - }, + 'change input.oe_import_file': 'loaded_file', + 'change input.oe_import_has_header, .oe_import_options input': 'settings_changed', 'click a.oe_import_toggle': function (e) { e.preventDefault(); var $el = $(e.target); @@ -109,14 +103,15 @@ openerp.base_import = function (instance) { this.do_action(_.extend(action, {target: 'new'})); }, // buttons - 'click .oe_import_validate': 'import_dryrun', - 'click .oe_import_import': 'do_import', + 'click .oe_import_validate': 'validate', + 'click .oe_import_import': 'import', 'click .oe_import_cancel': function (e) { e.preventDefault(); this.exit(); } }, init: function (parent, params) { + var self = this; this._super.apply(this, arguments); this.res_model = params.model; // import object id @@ -150,42 +145,48 @@ openerp.base_import = function (instance) { }, //- File & settings change section - file_update: function (e) { + onfile_loaded: function () { this.$('.oe_import_button').prop('disabled', true); if (!this.$('input.oe_import_file').val()) { return; } this.$el.removeClass('oe_import_preview oe_import_error'); jsonp(this.$el, { url: '/base_import/set_file' - }, this.proxy('settings_updated')); + }, this.proxy('settings_changed')); }, - settings_updated: function () { + onpreviewing: function () { + var self = this; + this.$('.oe_import_button').prop('disabled', true); this.$el.addClass('oe_import_with_file'); // TODO: test that write // succeeded? - this.Import.call( - 'parse_preview', [this.id, this.import_options()]) - .then(this.proxy('preview')); - }, - preview: function (result) { this.$el.removeClass('oe_import_preview_error oe_import_error'); this.$el.toggleClass( 'oe_import_noheaders', !this.$('input.oe_import_has_header').prop('checked')); - if (result.error) { - this.$('.oe_import_options').show(); - this.$el.addClass('oe_import_preview_error oe_import_error'); - this.$('.oe_import_error_report').html( - QWeb.render('ImportView.preview.error', result)) - .get(0).scrollIntoView(); - return; - } + this.Import.call( + 'parse_preview', [this.id, this.import_options()]) + .then(function (result) { + var signal = result.error ? 'preview_failed' : 'preview_succeeded'; + self[signal](result); + }); + }, + onpreview_error: function (event, from, to, result) { + this.$('.oe_import_options').show(); + this.$el.addClass('oe_import_preview_error oe_import_error'); + this.$('.oe_import_error_report').html( + QWeb.render('ImportView.preview.error', result)) + .get(0).scrollIntoView(); + }, + onpreview_success: function (event, from, to, result) { + this.$('.oe_import_import').removeClass('oe_highlight'); + this.$('.oe_import_validate').addClass('oe_highlight'); this.$('.oe_import_button').prop('disabled', false); this.$el.addClass('oe_import_preview'); this.$('table').html(QWeb.render('ImportView.preview', result)); if (result.headers.length === 1) { this.$('.oe_import_options').show(); - this.render_import_result([{ + this.onresults(null, null, null, [{ type: 'warning', message: _t("A single column was found in the file, this often means the file separator is incorrect") }]); @@ -225,7 +226,6 @@ openerp.base_import = function (instance) { width: 'resolve', dropdownCssClass: 'oe_import_selector' }); - //this.import_dryrun(); }, generate_fields_completion: function (root) { var basic = []; @@ -303,28 +303,31 @@ openerp.base_import = function (instance) { return this.Import.call( 'do', [this.id, fields, this.import_options()], options); }, - import_dryrun: function () { + onvalidate: function () { return this.call_import({ dryrun: true }) - .then(this.proxy('render_import_result')); + .then(this.proxy('validated')); }, - do_import: function () { + onimport: function () { var self = this; return this.call_import({ dryrun: false }).then(function (message) { if (!_.any(message, function (message) { return message.type === 'error' })) { - self.exit(); + self['import_succeeded'](); return; } - self.render_import_result(message); + self['import_failed'](message); }); }, + onimported: function () { + this.exit(); + }, exit: function () { this.do_action({ type: 'ir.actions.client', tag: 'history_back' }); }, - render_import_result: function (message) { + onresults: function (event, from, to, message) { var no_messages = _.isEmpty(message); this.$('.oe_import_import').toggleClass('oe_highlight', no_messages); this.$('.oe_import_validate').toggleClass('oe_highlight', !no_messages); @@ -386,4 +389,23 @@ openerp.base_import = function (instance) { })).get(0).scrollIntoView(); }, }); + // FSM-ize DataImport + StateMachine.create({ + target: instance.web.DataImport.prototype, + events: [ + { name: 'loaded_file', + from: ['none', 'file_loaded', 'preview_error', 'preview_success', 'results'], + to: 'file_loaded' }, + { name: 'settings_changed', + from: ['file_loaded', 'preview_error', 'preview_success', 'results'], + to: 'previewing' }, + { name: 'preview_failed', from: 'previewing', to: 'preview_error' }, + { name: 'preview_succeeded', from: 'previewing', to: 'preview_success' }, + { name: 'validate', from: 'preview_success', to: 'validating' }, + { name: 'validated', from: 'validating', to: 'results' }, + { name: 'import', from: ['preview_success', 'results'], to: 'importing' }, + { name: 'import_succeeded', from: 'importing', to: 'imported'}, + { name: 'import_failed', from: 'importing', to: 'results' } + ] + }) }; From 9c9d9781093cf35bb5abec0d605a02bbd9b3f108 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Wed, 3 Oct 2012 17:24:44 +0200 Subject: [PATCH 17/50] [IMP] relational field 'more values' dialog list features force display of pager and search view, make list non-selectable bzr revid: xmo@openerp.com-20121003152444-phnn9sc9nqo1ecpn --- addons/base_import/static/src/js/import.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/addons/base_import/static/src/js/import.js b/addons/base_import/static/src/js/import.js index 19d4e466cc7..2867242749c 100644 --- a/addons/base_import/static/src/js/import.js +++ b/addons/base_import/static/src/js/import.js @@ -100,7 +100,15 @@ openerp.base_import = function (instance) { : 'tree' ]; }); - this.do_action(_.extend(action, {target: 'new'})); + this.do_action(_.extend(action, { + target: 'new', + flags: { + search_view: true, + display_title: true, + pager: true, + list: {selectable: false} + } + })); }, // buttons 'click .oe_import_validate': 'validate', From 82e849e180c89698fd86fb1e6aa9a6d59119216e Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Thu, 4 Oct 2012 10:32:31 +0200 Subject: [PATCH 18/50] [FIX] base_import: should be possible to re-validate a file after a failed import or validation bzr revid: xmo@openerp.com-20121004083231-qyl8l58wyhb7g2c3 --- addons/base_import/static/src/js/import.js | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/base_import/static/src/js/import.js b/addons/base_import/static/src/js/import.js index 2867242749c..937565a24e8 100644 --- a/addons/base_import/static/src/js/import.js +++ b/addons/base_import/static/src/js/import.js @@ -410,6 +410,7 @@ openerp.base_import = function (instance) { { name: 'preview_failed', from: 'previewing', to: 'preview_error' }, { name: 'preview_succeeded', from: 'previewing', to: 'preview_success' }, { name: 'validate', from: 'preview_success', to: 'validating' }, + { name: 'validate', from: 'results', to: 'validating' }, { name: 'validated', from: 'validating', to: 'results' }, { name: 'import', from: ['preview_success', 'results'], to: 'importing' }, { name: 'import_succeeded', from: 'importing', to: 'imported'}, From 8f3db5bcf1f1eb6eb505e9847536fd8d26e46497 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Thu, 4 Oct 2012 12:22:36 +0200 Subject: [PATCH 19/50] [IMP] move file format options from below preview table to below file field bzr revid: xmo@openerp.com-20121004102236-auj053d38tp5fpvy --- addons/base_import/static/src/css/import.css | 2 +- addons/base_import/static/src/xml/import.xml | 26 +++++++++++--------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/addons/base_import/static/src/css/import.css b/addons/base_import/static/src/css/import.css index 25678cbe98a..21e598ff707 100644 --- a/addons/base_import/static/src/css/import.css +++ b/addons/base_import/static/src/css/import.css @@ -52,7 +52,7 @@ } .oe_import .oe_import_options label { display: inline-block; - width: 10em; + width: 8em; text-align: right; } diff --git a/addons/base_import/static/src/xml/import.xml b/addons/base_import/static/src/xml/import.xml index b0eea1fcf75..91debd64897 100644 --- a/addons/base_import/static/src/xml/import.xml +++ b/addons/base_import/static/src/xml/import.xml @@ -24,6 +24,20 @@ +
    + + File Format Options… +
    +

    + + + +

    +
    +

    Map your data to OpenERP

    @@ -38,18 +52,6 @@
    - - File Format Options… -
    -

    - - - -

    -

    Frequently Asked Questions

    From 1b17b59f50b73c927f1283901003d6ea793785af Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Thu, 4 Oct 2012 13:50:24 +0200 Subject: [PATCH 20/50] [IMP] base_import: provide an encoding picker bzr revid: xmo@openerp.com-20121004115024-m77q5c95i12q3qkm --- addons/base_import/static/src/js/import.js | 23 ++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/addons/base_import/static/src/js/import.js b/addons/base_import/static/src/js/import.js index 937565a24e8..551196678a3 100644 --- a/addons/base_import/static/src/js/import.js +++ b/addons/base_import/static/src/js/import.js @@ -128,6 +128,7 @@ openerp.base_import = function (instance) { }, start: function () { var self = this; + this.setup_encoding_picker(); return $.when( this._super(), @@ -139,6 +140,25 @@ openerp.base_import = function (instance) { }) ) }, + setup_encoding_picker: function () { + this.$('input.oe_import_encoding').select2({ + width: '160px', + query: function (q) { + var make = function (term) { return {id: term, text: term}; }; + var suggestions = _.map( + ('utf-8 utf-16 windows-1252 latin1 latin2 big5 ' + + 'gb18030 shift_jis windows-1251 koir8_r').split(/\s+/), + make); + if (q.term) { + suggestions.unshift(make(q.term)); + } + q.callback({results: suggestions}); + }, + initSelection: function (e, c) { + return c({id: 'utf-8', text: 'utf-8'}); + } + }).select2('val', 'utf-8'); + }, import_options: function () { var self = this; @@ -182,8 +202,7 @@ openerp.base_import = function (instance) { this.$('.oe_import_options').show(); this.$el.addClass('oe_import_preview_error oe_import_error'); this.$('.oe_import_error_report').html( - QWeb.render('ImportView.preview.error', result)) - .get(0).scrollIntoView(); + QWeb.render('ImportView.preview.error', result)); }, onpreview_success: function (event, from, to, result) { this.$('.oe_import_import').removeClass('oe_highlight'); From 25f695a650079d68fabb96a923c4d7411a27cd98 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Thu, 4 Oct 2012 15:38:40 +0200 Subject: [PATCH 21/50] [IMP] pass restore callback to import action so that the listview can reload itself after coming back from an import (successful or not) and show the results of the import. bzr revid: xmo@openerp.com-20121004133840-a2uy4s5qhpqqvp8h --- addons/base_import/static/src/js/import.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/addons/base_import/static/src/js/import.js b/addons/base_import/static/src/js/import.js index 551196678a3..5980eb2384c 100644 --- a/addons/base_import/static/src/js/import.js +++ b/addons/base_import/static/src/js/import.js @@ -53,6 +53,8 @@ openerp.base_import = function (instance) { params: { model: self.dataset.model } + }, void 0, void 0, function () { + self.reload(); }); return false; }); From a3f1a64c45568fe0fe2f0ceecb41887c4b61a1a4 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Fri, 5 Oct 2012 10:34:40 +0200 Subject: [PATCH 22/50] [IMP] make base_import auto-install bzr revid: xmo@openerp.com-20121005083440-xenjci6qag7bkk3n --- addons/base_import/__openerp__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/base_import/__openerp__.py b/addons/base_import/__openerp__.py index bb527e7b49d..f5a707650d8 100644 --- a/addons/base_import/__openerp__.py +++ b/addons/base_import/__openerp__.py @@ -26,7 +26,7 @@ Re-implement openerp's file import system: 'author': 'OpenERP SA', 'depends': ['base'], 'installable': True, - 'auto_install': False, # set to true and allow uninstall? + 'auto_install': True, 'css': [ 'static/lib/select2/select2.css', 'static/src/css/import.css', From 3f0c2c1bb7f582498781e2f9306c12cc1e05637c Mon Sep 17 00:00:00 2001 From: "Atul Patel (OpenERP)" Date: Fri, 5 Oct 2012 19:01:29 +0530 Subject: [PATCH 23/50] [IMP]: Enble stock moves menu in stock. bzr revid: atp@tinyerp.com-20121005133129-iik7g60lme14ccm3 --- addons/stock/security/stock_security.xml | 2 ++ addons/stock/stock_view.xml | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/addons/stock/security/stock_security.xml b/addons/stock/security/stock_security.xml index c9f8a03a378..d8f9c2973db 100644 --- a/addons/stock/security/stock_security.xml +++ b/addons/stock/security/stock_security.xml @@ -21,6 +21,8 @@ Manage Logistic Serial Numbers + + diff --git a/addons/stock/stock_view.xml b/addons/stock/stock_view.xml index f5320a963c7..ad62cc3d4f0 100644 --- a/addons/stock/stock_view.xml +++ b/addons/stock/stock_view.xml @@ -272,7 +272,7 @@ + sequence="3" groups="stock.group_tracking_lot"/> Date: Mon, 8 Oct 2012 13:06:08 +0530 Subject: [PATCH 24/50] [FIX]: Remove groups to enable stock moves menu bzr revid: atp@tinyerp.com-20121008073608-0rnmqkz82631tbxj --- addons/stock/security/stock_security.xml | 2 -- addons/stock/stock_view.xml | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/addons/stock/security/stock_security.xml b/addons/stock/security/stock_security.xml index d8f9c2973db..c9f8a03a378 100644 --- a/addons/stock/security/stock_security.xml +++ b/addons/stock/security/stock_security.xml @@ -21,8 +21,6 @@ Manage Logistic Serial Numbers - - diff --git a/addons/stock/stock_view.xml b/addons/stock/stock_view.xml index ad62cc3d4f0..1a3f8e57d5c 100644 --- a/addons/stock/stock_view.xml +++ b/addons/stock/stock_view.xml @@ -272,7 +272,7 @@ + sequence="3"/> Date: Mon, 8 Oct 2012 15:19:24 +0530 Subject: [PATCH 25/50] [IMP] Remove add_last in on_created method bzr revid: ggh@tinyerp.com-20121008094924-uawry36sh9ffz8ut --- addons/web/static/src/js/view_form.js | 8 +++++--- addons/web_calendar/static/src/js/calendar.js | 2 +- addons/web_kanban/static/src/js/kanban.js | 4 ++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index b41039361c0..366b2e7a9e9 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -131,6 +131,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM e.preventDefault(); } }); + self.on('on_rec_create', self, self.on_created); }, destroy: function() { _.each(this.get_widgets(), function(w) { @@ -778,7 +779,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM var def = $.Deferred(); $.when(this.has_been_loaded).then(function() { self.dataset.call('copy', [self.datarecord.id, {}, self.dataset.context]).then(function(new_id) { - return self.on_created({ result : new_id }); + return self.trigger('on_rec_create',{ result : new_id }); }).then(function() { return self.to_edit_mode(); }).then(function() { @@ -859,7 +860,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM if (!self.datarecord.id) { // Creation save save_deferral = self.dataset.create(values).pipe(function(r) { - return self.on_created(r, prepend_on_create); + return self.trigger('on_rec_create', r, prepend_on_create); }, null); } else if (_.isEmpty(values) && ! self.force_dirty) { // Not dirty, noop save @@ -1622,12 +1623,13 @@ instance.web.form.FormDialog = instance.web.Dialog.extend({ return this; }, start: function() { + var self = this; this._super(); this.form = new instance.web.FormView(this, this.dataset, this.view_id, { pager: false }); this.form.appendTo(this.$el); - this.form.on_created.add_last(this.on_form_dialog_saved); + this.form.on('on_rec_create', self, this.on_form_dialog_saved); this.form.on_saved.add_last(this.on_form_dialog_saved); return this; }, diff --git a/addons/web_calendar/static/src/js/calendar.js b/addons/web_calendar/static/src/js/calendar.js index 81533413312..35cac441b35 100644 --- a/addons/web_calendar/static/src/js/calendar.js +++ b/addons/web_calendar/static/src/js/calendar.js @@ -458,7 +458,7 @@ instance.web_calendar.CalendarFormDialog = instance.web.Dialog.extend({ pager: false }); var def = this.form.appendTo(this.$el); - this.form.on_created.add_last(this.on_form_dialog_saved); + this.form.on('on_rec_create', self, this.on_form_dialog_saved); this.form.on_saved.add_last(this.on_form_dialog_saved); this.form.on_button_cancel = function() { self.close(); diff --git a/addons/web_kanban/static/src/js/kanban.js b/addons/web_kanban/static/src/js/kanban.js index 41cc366226f..45f5c98bf51 100644 --- a/addons/web_kanban/static/src/js/kanban.js +++ b/addons/web_kanban/static/src/js/kanban.js @@ -195,7 +195,7 @@ instance.web_kanban.KanbanView = instance.web.View.extend({ var am = instance.webclient.action_manager; var form = am.dialog_widget.views.form.controller; form.on_button_cancel.add_last(am.dialog.on_close); - form.on_created.add_last(function(r) { + form.on('on_rec_create', self, function(r) { (new instance.web.DataSet(self, self.group_by_field.relation)).name_get([r.result]).then(function(new_record) { am.dialog.on_close(); var domain = self.dataset.domain.slice(0); @@ -673,7 +673,7 @@ instance.web_kanban.KanbanGroup = instance.web.Widget.extend({ var am = instance.webclient.action_manager; var form = am.dialog_widget.views.form.controller; form.on_button_cancel.add_last(am.dialog.on_close); - form.on_saved.add_last(function() { + form.on('on_saved', self, function() { am.dialog.on_close(); self.view.do_reload(); }); From 4dd9a36f6e88d23344deaecbf997fc2ec63a64cc Mon Sep 17 00:00:00 2001 From: ggh-openerp Date: Mon, 8 Oct 2012 16:33:46 +0530 Subject: [PATCH 26/50] [IMP] Remove add_last in on_saved method bzr revid: ggh@tinyerp.com-20121008110346-r0dzmjy3161bxglb --- addons/web/static/src/js/view_form.js | 5 +++-- addons/web_calendar/static/src/js/calendar.js | 2 +- addons/web_kanban/static/src/js/kanban.js | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index b41039361c0..ce2e1ac5689 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -131,6 +131,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM e.preventDefault(); } }); + self.on("on_rec_save", self, self.on_saved); }, destroy: function() { _.each(this.get_widgets(), function(w) { @@ -868,7 +869,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM self.force_dirty = false; // Write save save_deferral = self.dataset.write(self.datarecord.id, values, {}).pipe(function(r) { - return self.on_saved(r); + return self.trigger('on_rec_save', r); }, null); } return save_deferral; @@ -1628,7 +1629,7 @@ instance.web.form.FormDialog = instance.web.Dialog.extend({ }); this.form.appendTo(this.$el); this.form.on_created.add_last(this.on_form_dialog_saved); - this.form.on_saved.add_last(this.on_form_dialog_saved); + this.form.on('on_rec_save', this, this.on_form_dialog_saved); return this; }, select_id: function(id) { diff --git a/addons/web_calendar/static/src/js/calendar.js b/addons/web_calendar/static/src/js/calendar.js index 81533413312..37c49462b59 100644 --- a/addons/web_calendar/static/src/js/calendar.js +++ b/addons/web_calendar/static/src/js/calendar.js @@ -459,7 +459,7 @@ instance.web_calendar.CalendarFormDialog = instance.web.Dialog.extend({ }); var def = this.form.appendTo(this.$el); this.form.on_created.add_last(this.on_form_dialog_saved); - this.form.on_saved.add_last(this.on_form_dialog_saved); + this.form.on('on_rec_save', self, this.on_form_dialog_saved); this.form.on_button_cancel = function() { self.close(); } diff --git a/addons/web_kanban/static/src/js/kanban.js b/addons/web_kanban/static/src/js/kanban.js index 41cc366226f..438b1f7cb14 100644 --- a/addons/web_kanban/static/src/js/kanban.js +++ b/addons/web_kanban/static/src/js/kanban.js @@ -673,7 +673,7 @@ instance.web_kanban.KanbanGroup = instance.web.Widget.extend({ var am = instance.webclient.action_manager; var form = am.dialog_widget.views.form.controller; form.on_button_cancel.add_last(am.dialog.on_close); - form.on_saved.add_last(function() { + form.on('on_rec_save', self, function() { am.dialog.on_close(); self.view.do_reload(); }); From 775fe69fc10603c8b859e2c2554827f74f0405fc Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Mon, 8 Oct 2012 15:08:56 +0200 Subject: [PATCH 27/50] [IMP] base_import: always open CSV link in new window bzr revid: xmo@openerp.com-20121008130856-fw0p92lofx7u27b2 --- addons/base_import/static/src/xml/import.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/base_import/static/src/xml/import.xml b/addons/base_import/static/src/xml/import.xml index 91debd64897..adca0579f8f 100644 --- a/addons/base_import/static/src/xml/import.xml +++ b/addons/base_import/static/src/xml/import.xml @@ -18,7 +18,7 @@

    Upload your file

    Select the .CSV + class="oe_import_csv" target="_blank">.CSV file to import. If you need a sample importable file, you can use the export tool to generate one.

    From 5ab21e13a36902c13905ff92bb1cc0d728dbd467 Mon Sep 17 00:00:00 2001 From: ggh-openerp Date: Tue, 9 Oct 2012 11:46:18 +0530 Subject: [PATCH 28/50] [IMP] Remove add_last in on_unlink method bzr revid: ggh@tinyerp.com-20121009061618-ohsjlzf14jpqws2q --- addons/web/static/src/js/data.js | 4 +++- addons/web/static/src/js/view_form.js | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/addons/web/static/src/js/data.js b/addons/web/static/src/js/data.js index 220d42737da..79f909c0908 100644 --- a/addons/web/static/src/js/data.js +++ b/addons/web/static/src/js/data.js @@ -690,9 +690,11 @@ instance.web.DataSet = instance.web.CallbackEnabled.extend({ instance.web.DataSetStatic = instance.web.DataSet.extend({ init: function(parent, model, context, ids) { + var self = this; this._super(parent, model, context); // all local records this.ids = ids || []; + self.on("on_rec_unlink", self, self.on_unlink); }, read_slice: function (fields, options) { options = options || {}; @@ -711,7 +713,7 @@ instance.web.DataSetStatic = instance.web.DataSet.extend({ } }, unlink: function(ids) { - this.on_unlink(ids); + this.trigger('on_rec_unlink', ids); return $.Deferred().resolve({result: true}); }, on_unlink: function(ids) { diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index 6a16c06095d..0266af3d40e 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -3998,7 +3998,7 @@ instance.web.form.FieldMany2Many = instance.web.form.AbstractField.extend({ this.dataset = new instance.web.form.Many2ManyDataSet(this, this.field.relation); this.dataset.m2m = this; - this.dataset.on_unlink.add_last(function(ids) { + this.dataset.on('on_rec_unlink', self, function(ids) { self.dataset_changed(); }); @@ -4131,7 +4131,7 @@ instance.web.form.FieldMany2ManyKanban = instance.web.form.AbstractField.extend( this.dataset = new instance.web.form.Many2ManyDataSet(this, this.field.relation); this.dataset.m2m = this; - this.dataset.on_unlink.add_last(function(ids) { + this.dataset.on('on_rec_unlink', self, function(ids) { self.dataset_changed(); }); From f168998a49cbced240962f1aca86f2c89f665549 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 9 Oct 2012 11:44:11 +0200 Subject: [PATCH 29/50] [FIX] l10n_uk: import doesn't skip empty cells anymore, so fix import which relied on default value being set on empty cell bzr revid: xmo@openerp.com-20121009094411-6eji2zzp3r1afx9h --- addons/l10n_uk/data/account.account.type.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/l10n_uk/data/account.account.type.csv b/addons/l10n_uk/data/account.account.type.csv index 0827975b22f..379656ece39 100644 --- a/addons/l10n_uk/data/account.account.type.csv +++ b/addons/l10n_uk/data/account.account.type.csv @@ -10,4 +10,4 @@ "account_type_output_tax","Output Tax","Output Tax","liability","Unreconciled" "account_type_input_tax","Input Tax","Input Tax","asset","Unreconciled" "account_type_profit_and_loss","Profit and Loss","Profit and Loss","none","None" -"account_type_view","View","view",,"None" +"account_type_view","View","view","none","None" From 4dd9a0529e79eccb7670a180c5d88fad144fa4c9 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Wed, 10 Oct 2012 12:18:36 +0200 Subject: [PATCH 30/50] [ADD] reload file button next to the file input, as webkit browsers and MSIE don't trigger change when a file input is re-set to thee same file Using other events (e.g. 'click') is not kosher as the event is triggered long before the file is picked, the alternative is to use the File API and regularly check the file in the input to see if it's been altered (by storing a crc) and re-pushing it if the hash is different. Of course this has other issues (risks catching the file mid-edition...) A third alternative is, once a file has been uploaded, to clear and re-insert the corresponding file input. This means the file input will *always* be empty bzr revid: xmo@openerp.com-20121010101836-qtqmcc5n5zblgmcp --- addons/base_import/static/src/css/import.css | 19 +++++++++++++++++++ addons/base_import/static/src/js/import.js | 3 ++- addons/base_import/static/src/xml/import.xml | 1 + 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/addons/base_import/static/src/css/import.css b/addons/base_import/static/src/css/import.css index 21e598ff707..3b4daf815e5 100644 --- a/addons/base_import/static/src/css/import.css +++ b/addons/base_import/static/src/css/import.css @@ -60,3 +60,22 @@ .oe_import_selector li { margin: 0; padding: 0; } + +.oe_import .oe_import_file_reload { + font-size: 1px; + letter-spacing: -1px; + color: transparent; + font-weight: normal; + position: relative; + padding: 0; + height: 19px; + width: 20px; +} +.oe_import .oe_import_file_reload:before { + font: 26px "mnmliconsRegular"; + content: "Q"; + color: #4C4C4C; + position: absolute; + top: -6px; + left: 2px; +} diff --git a/addons/base_import/static/src/js/import.js b/addons/base_import/static/src/js/import.js index 5980eb2384c..0a60fe18ffb 100644 --- a/addons/base_import/static/src/js/import.js +++ b/addons/base_import/static/src/js/import.js @@ -73,7 +73,8 @@ openerp.base_import = function (instance) { ], events: { // 'change .oe_import_grid input': 'import_dryrun', - 'change input.oe_import_file': 'loaded_file', + 'change .oe_import_file': 'loaded_file', + 'click .oe_import_file_reload': 'loaded_file', 'change input.oe_import_has_header, .oe_import_options input': 'settings_changed', 'click a.oe_import_toggle': function (e) { e.preventDefault(); diff --git a/addons/base_import/static/src/xml/import.xml b/addons/base_import/static/src/xml/import.xml index adca0579f8f..902478468e1 100644 --- a/addons/base_import/static/src/xml/import.xml +++ b/addons/base_import/static/src/xml/import.xml @@ -24,6 +24,7 @@ +
    File Format Options… From e2d3d617a96e416751c15e42d3fbebedfdc7e00c Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Wed, 10 Oct 2012 12:49:52 +0200 Subject: [PATCH 31/50] [IMP] account: added monetary widget on invoices form view bzr revid: qdp-launchpad@openerp.com-20121010104952-jxy17zagby2jp0w2 --- addons/account/account_invoice_view.xml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/addons/account/account_invoice_view.xml b/addons/account/account_invoice_view.xml index 8421409d4ce..8516fcd96ae 100644 --- a/addons/account/account_invoice_view.xml +++ b/addons/account/account_invoice_view.xml @@ -211,17 +211,17 @@ - +
    - - + + - +
    @@ -368,16 +368,16 @@ - +
    - - - + + +
    From 7c6e893a3952b206ba6f8e6301336ceced1b3f38 Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Wed, 10 Oct 2012 12:56:19 +0200 Subject: [PATCH 32/50] [IMP] account: added monetary widget on account.move.line and cash registers bzr revid: qdp-launchpad@openerp.com-20121010105619-fk13ba9ex0f0ihpv --- addons/account/account_view.xml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/addons/account/account_view.xml b/addons/account/account_view.xml index 3391158696a..d98b53ebbbd 100644 --- a/addons/account/account_view.xml +++ b/addons/account/account_view.xml @@ -1127,8 +1127,8 @@ - - + + @@ -1174,8 +1174,8 @@ - - + + @@ -2564,7 +2564,7 @@ action = pool.get('res.config').next(cr, uid, [], context) - + @@ -2626,12 +2626,12 @@ action = pool.get('res.config').next(cr, uid, [], context) - - - + + + - + From 1bb568d22e4fa493f3fa388928f47af09e24d90a Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Wed, 10 Oct 2012 13:12:05 +0200 Subject: [PATCH 33/50] [IMP] sale, sale_margin: added monetary widget on sale order form view bzr revid: qdp-launchpad@openerp.com-20121010111205-eokyh1haa69tgrfl --- addons/sale/sale.py | 10 ++++++++-- addons/sale/sale_view.xml | 7 ++++--- addons/sale_margin/sale_margin_view.xml | 2 +- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/addons/sale/sale.py b/addons/sale/sale.py index ed7a2835425..9ba6c43a588 100644 --- a/addons/sale/sale.py +++ b/addons/sale/sale.py @@ -201,6 +201,7 @@ class sale_order(osv.osv): help="""This field controls how invoice and delivery operations are synchronized. - With 'Before Delivery', a draft invoice is created, and it must be paid before delivery."""), 'pricelist_id': fields.many2one('product.pricelist', 'Pricelist', required=True, readonly=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}, help="Pricelist for current sales order."), + 'currency_id': fields.related('pricelist_id', 'currency_id', type="many2one", relation="res.currency", readonly=True, required=True), 'project_id': fields.many2one('account.analytic.account', 'Contract/Analytic Account', readonly=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}, help="The analytic account related to a sales order."), 'order_line': fields.one2many('sale.order.line', 'order_id', 'Order Lines', readonly=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}), @@ -264,13 +265,18 @@ class sale_order(osv.osv): return osv.osv.unlink(self, cr, uid, unlink_ids, context=context) def onchange_pricelist_id(self, cr, uid, ids, pricelist_id, order_lines, context=None): - if (not pricelist_id) or (not order_lines): + if not pricelist_id: return {} + value = { + 'currency_id': self.pool.get('product.pricelist').browse(cr, uid, pricelist_id, context=context).currency_id.id + } + if not order_lines: + return {'value': value} warning = { 'title': _('Pricelist Warning!'), 'message' : _('If you change the pricelist of this order (and eventually the currency), prices of existing order lines will not be updated.') } - return {'warning': warning} + return {'warning': warning, 'value': value} def onchange_partner_id(self, cr, uid, ids, part): if not part: diff --git a/addons/sale/sale_view.xml b/addons/sale/sale_view.xml index a9ebca876a9..8b89e8047cb 100644 --- a/addons/sale/sale_view.xml +++ b/addons/sale/sale_view.xml @@ -184,6 +184,7 @@ + @@ -261,14 +262,14 @@ - - + + - + diff --git a/addons/sale_margin/sale_margin_view.xml b/addons/sale_margin/sale_margin_view.xml index 69f49bd48ea..6aa34bae26c 100644 --- a/addons/sale_margin/sale_margin_view.xml +++ b/addons/sale_margin/sale_margin_view.xml @@ -11,7 +11,7 @@ From 155680a15871af3f06abaa461c7e531c1f2adc8d Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Wed, 10 Oct 2012 13:20:13 +0200 Subject: [PATCH 34/50] [IMP] purchase: added monetary widget on purchase order form view bzr revid: qdp-launchpad@openerp.com-20121010112013-d6z1iq6hpjgdle63 --- addons/purchase/purchase.py | 6 ++++++ addons/purchase/purchase_view.xml | 9 +++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/addons/purchase/purchase.py b/addons/purchase/purchase.py index d654078a055..c0516d09de3 100644 --- a/addons/purchase/purchase.py +++ b/addons/purchase/purchase.py @@ -166,6 +166,7 @@ class purchase_order(osv.osv): 'warehouse_id': fields.many2one('stock.warehouse', 'Destination Warehouse', states={'confirmed':[('readonly',True)], 'approved':[('readonly',True)],'done':[('readonly',True)]}), 'location_id': fields.many2one('stock.location', 'Destination', required=True, domain=[('usage','<>','view')]), 'pricelist_id':fields.many2one('product.pricelist', 'Pricelist', required=True, states={'confirmed':[('readonly',True)], 'approved':[('readonly',True)],'done':[('readonly',True)]}, help="The pricelist sets the currency used for this purchase order. It also computes the supplier price for the selected products/quantities."), + 'currency_id': fields.related('pricelist_id', 'currency_id', type="many2one", relation="res.currency", readonly=True, required=True), 'state': fields.selection(STATE_SELECTION, 'Status', readonly=True, help="The state of the purchase order or the quotation request. A quotation is a purchase order in a 'Draft' state. Then the order has to be confirmed by the user, the state switch to 'Confirmed'. Then the supplier must confirm the order to change the state to 'Approved'. When the purchase order is paid and received, the state becomes 'Done'. If a cancel action occurs in the invoice or in the reception of goods, the state becomes in exception.", select=True), 'order_line': fields.one2many('purchase.order.line', 'order_id', 'Order Lines', states={'approved':[('readonly',True)],'done':[('readonly',True)]}), 'validator' : fields.many2one('res.users', 'Validated by', readonly=True), @@ -246,6 +247,11 @@ class purchase_order(osv.osv): def button_dummy(self, cr, uid, ids, context=None): return True + def onchange_pricelist(self, cr, uid, ids, pricelist_id, context=None): + if not pricelist_id: + return {} + return {'value': {'currency_id': self.pool.get('product.pricelist').browse(cr, uid, pricelist_id, context=context).currency_id.id}} + def onchange_dest_address_id(self, cr, uid, ids, address_id): if not address_id: return {} diff --git a/addons/purchase/purchase_view.xml b/addons/purchase/purchase_view.xml index bfff06f5eaf..446c17578cb 100644 --- a/addons/purchase/purchase_view.xml +++ b/addons/purchase/purchase_view.xml @@ -223,7 +223,8 @@ - + + @@ -249,14 +250,14 @@ - - + + - +