[MERGE] Forward-port of latest 7.0 bugfixes, up to rev. 9846 revid:dle@openerp.com-20140217124044-o8sgz1esfqeha01f

bzr revid: dle@openerp.com-20140214100922-m6rf7c6x85nv67sl
bzr revid: dle@openerp.com-20140214114713-oab4kbearvv7g3nh
bzr revid: dle@openerp.com-20140214131810-9abebxpfeoga1crn
bzr revid: dle@openerp.com-20140217124230-ov201kfep88f5tn7
This commit is contained in:
Denis Ledoux 2014-02-17 13:42:30 +01:00
commit 0ef17beed0
8 changed files with 125 additions and 65 deletions

View File

@ -22,6 +22,7 @@ openerp.account.quickadd = function (instance) {
start:function(){ start:function(){
var tmp = this._super.apply(this, arguments); var tmp = this._super.apply(this, arguments);
var self = this; var self = this;
var defs = [];
this.$el.parent().prepend(QWeb.render("AccountMoveLineQuickAdd", {widget: this})); this.$el.parent().prepend(QWeb.render("AccountMoveLineQuickAdd", {widget: this}));
this.$el.parent().find('.oe_account_select_journal').change(function() { this.$el.parent().find('.oe_account_select_journal').change(function() {
@ -41,11 +42,17 @@ openerp.account.quickadd = function (instance) {
self.$el.parent().find('.oe_account_select_period').removeAttr('disabled'); self.$el.parent().find('.oe_account_select_period').removeAttr('disabled');
}); });
var mod = new instance.web.Model("account.move.line", self.dataset.context, self.dataset.domain); var mod = new instance.web.Model("account.move.line", self.dataset.context, self.dataset.domain);
mod.call("default_get", [['journal_id','period_id'],self.dataset.context]).then(function(result) { defs.push(mod.call("default_get", [['journal_id','period_id'],self.dataset.context]).then(function(result) {
self.current_period = result['period_id']; self.current_period = result['period_id'];
self.current_journal = result['journal_id']; self.current_journal = result['journal_id'];
}); }));
return tmp; defs.push(mod.call("list_journals", []).then(function(result) {
self.journals = result;
}));
defs.push(mod.call("list_periods", []).then(function(result) {
self.periods = result;
}));
return $.when(tmp, defs);
}, },
do_search: function(domain, context, group_by) { do_search: function(domain, context, group_by) {
var self = this; var self = this;
@ -53,34 +60,27 @@ openerp.account.quickadd = function (instance) {
this.last_context = context; this.last_context = context;
this.last_group_by = group_by; this.last_group_by = group_by;
this.old_search = _.bind(this._super, this); this.old_search = _.bind(this._super, this);
var mod = new instance.web.Model("account.move.line", context, domain); var o;
return $.when(mod.call("list_journals", []).then(function(result) { self.$el.parent().find('.oe_account_select_journal').children().remove().end();
self.journals = result; self.$el.parent().find('.oe_account_select_journal').append(new Option('', ''));
}),mod.call("list_periods", []).then(function(result) { for (var i = 0;i < self.journals.length;i++){
self.periods = result; o = new Option(self.journals[i][1], self.journals[i][0]);
})).then(function () { if (self.journals[i][0] === self.current_journal){
var o; self.current_journal_type = self.journals[i][2];
self.$el.parent().find('.oe_account_select_journal').children().remove().end(); self.current_journal_currency = self.journals[i][3];
self.$el.parent().find('.oe_account_select_journal').append(new Option('', '')); self.current_journal_analytic = self.journals[i][4];
for (var i = 0;i < self.journals.length;i++){ $(o).attr('selected',true);
o = new Option(self.journals[i][1], self.journals[i][0]);
if (self.journals[i][0] === self.current_journal){
self.current_journal_type = self.journals[i][2];
self.current_journal_currency = self.journals[i][3];
self.current_journal_analytic = self.journals[i][4];
$(o).attr('selected',true);
}
self.$el.parent().find('.oe_account_select_journal').append(o);
} }
self.$el.parent().find('.oe_account_select_period').children().remove().end(); self.$el.parent().find('.oe_account_select_journal').append(o);
self.$el.parent().find('.oe_account_select_period').append(new Option('', '')); }
for (var i = 0;i < self.periods.length;i++){ self.$el.parent().find('.oe_account_select_period').children().remove().end();
o = new Option(self.periods[i][1], self.periods[i][0]); self.$el.parent().find('.oe_account_select_period').append(new Option('', ''));
self.$el.parent().find('.oe_account_select_period').append(o); for (var i = 0;i < self.periods.length;i++){
} o = new Option(self.periods[i][1], self.periods[i][0]);
self.$el.parent().find('.oe_account_select_period').val(self.current_period).attr('selected',true); self.$el.parent().find('.oe_account_select_period').append(o);
return self.search_by_journal_period(); }
}); self.$el.parent().find('.oe_account_select_period').val(self.current_period).attr('selected',true);
return self.search_by_journal_period();
}, },
search_by_journal_period: function() { search_by_journal_period: function() {
var self = this; var self = this;
@ -93,7 +93,9 @@ openerp.account.quickadd = function (instance) {
self.last_context["journal_type"] = self.current_journal_type; self.last_context["journal_type"] = self.current_journal_type;
self.last_context["currency"] = self.current_journal_currency; self.last_context["currency"] = self.current_journal_currency;
self.last_context["analytic_journal_id"] = self.current_journal_analytic; self.last_context["analytic_journal_id"] = self.current_journal_analytic;
return self.old_search(new instance.web.CompoundDomain(self.last_domain, domain), self.last_context, self.last_group_by); var compound_domain = new instance.web.CompoundDomain(self.last_domain, domain);
self.dataset.domain = compound_domain.eval();
return self.old_search(compound_domain, self.last_context, self.last_group_by);
}, },
}); });
}; };

View File

@ -54,7 +54,7 @@ _ref_vat = {
'gr': 'GR12345670', 'gr': 'GR12345670',
'hu': 'HU12345676', 'hu': 'HU12345676',
'hr': 'HR01234567896', # Croatia, contributed by Milan Tribuson 'hr': 'HR01234567896', # Croatia, contributed by Milan Tribuson
'ie': 'IE1234567T', 'ie': 'IE1234567FA',
'it': 'IT12345670017', 'it': 'IT12345670017',
'lt': 'LT123456715', 'lt': 'LT123456715',
'lu': 'LU12345613', 'lu': 'LU12345613',
@ -190,6 +190,34 @@ class res_partner(osv.osv):
return check == int(num[8]) return check == int(num[8])
return False return False
def _ie_check_char(self, vat):
vat = vat.zfill(8)
extra = 0
if vat[7] not in ' W':
if vat[7].isalpha():
extra = 9 * (ord(vat[7]) - 64)
else:
# invalid
return -1
checksum = extra + sum((8-i) * int(x) for i, x in enumerate(vat[:7]))
return 'WABCDEFGHIJKLMNOPQRSTUV'[checksum % 23]
def check_vat_ie(self, vat):
""" Temporary Ireland VAT validation to support the new format
introduced in January 2013 in Ireland, until upstream is fixed.
TODO: remove when fixed upstream"""
if len(vat) not in (8, 9) or not vat[2:7].isdigit():
return False
if len(vat) == 8:
# Normalize pre-2013 numbers: final space or 'W' not significant
vat += ' '
if vat[:7].isdigit():
return vat[7] == self._ie_check_char(vat[:7] + vat[8])
elif vat[1] in (string.ascii_uppercase + '+*'):
# Deprecated format
# See http://www.revenue.ie/en/online/third-party-reporting/reporting-payment-details/faqs.html#section3
return vat[7] == self._ie_check_char(vat[2:7] + vat[0] + vat[8])
return False
# Mexican VAT verification, contributed by <moylop260@hotmail.com> # Mexican VAT verification, contributed by <moylop260@hotmail.com>
# and Panos Christeas <p_christ@hol.gr> # and Panos Christeas <p_christ@hol.gr>

View File

@ -329,6 +329,7 @@ class crm_lead(format_address, osv.osv):
'phone': partner.phone, 'phone': partner.phone,
'mobile': partner.mobile, 'mobile': partner.mobile,
'fax': partner.fax, 'fax': partner.fax,
'zip': partner.zip,
} }
return {'value': values} return {'value': values}

View File

@ -256,6 +256,7 @@ class event_event(osv.osv):
] ]
def onchange_event_type(self, cr, uid, ids, type_event, context=None): def onchange_event_type(self, cr, uid, ids, type_event, context=None):
values = {}
if type_event: if type_event:
type_info = self.pool.get('event.type').browse(cr,uid,type_event,context) type_info = self.pool.get('event.type').browse(cr,uid,type_event,context)
dic ={ dic ={
@ -265,7 +266,8 @@ class event_event(osv.osv):
'register_min': type_info.default_registration_min, 'register_min': type_info.default_registration_min,
'register_max': type_info.default_registration_max, 'register_max': type_info.default_registration_max,
} }
return {'value': dic} values.update(dic)
return values
def on_change_address_id(self, cr, uid, ids, address_id, context=None): def on_change_address_id(self, cr, uid, ids, address_id, context=None):
values = {} values = {}

View File

@ -187,7 +187,7 @@ openerp_mailgate: "|/path/to/openerp-mailgate.py --host=localhost -u %(uid)d -p
for server in self.browse(cr, uid, ids, context=context): for server in self.browse(cr, uid, ids, context=context):
_logger.info('start checking for new emails on %s server %s', server.type, server.name) _logger.info('start checking for new emails on %s server %s', server.type, server.name)
context.update({'fetchmail_server_id': server.id, 'server_type': server.type}) context.update({'fetchmail_server_id': server.id, 'server_type': server.type})
count = 0 count, failed = 0, 0
imap_server = False imap_server = False
pop_server = False pop_server = False
if server.type == 'imap': if server.type == 'imap':
@ -196,20 +196,26 @@ openerp_mailgate: "|/path/to/openerp-mailgate.py --host=localhost -u %(uid)d -p
imap_server.select() imap_server.select()
result, data = imap_server.search(None, '(UNSEEN)') result, data = imap_server.search(None, '(UNSEEN)')
for num in data[0].split(): for num in data[0].split():
res_id = None
result, data = imap_server.fetch(num, '(RFC822)') result, data = imap_server.fetch(num, '(RFC822)')
res_id = mail_thread.message_process(cr, uid, server.object_id.model, imap_server.store(num, '-FLAGS', '\\Seen')
data[0][1], try:
save_original=server.original, res_id = mail_thread.message_process(cr, uid, server.object_id.model,
strip_attachments=(not server.attach), data[0][1],
context=context) save_original=server.original,
strip_attachments=(not server.attach),
context=context)
except Exception:
_logger.exception('Failed to process mail from %s server %s.', server.type, server.name)
failed += 1
if res_id and server.action_id: if res_id and server.action_id:
action_pool.run(cr, uid, [server.action_id.id], {'active_id': res_id, 'active_ids':[res_id], 'active_model': context.get("thread_model", server.object_id.model)}) action_pool.run(cr, uid, [server.action_id.id], {'active_id': res_id, 'active_ids': [res_id], 'active_model': context.get("thread_model", server.object_id.model)})
imap_server.store(num, '+FLAGS', '\\Seen') imap_server.store(num, '+FLAGS', '\\Seen')
cr.commit() cr.commit()
count += 1 count += 1
_logger.info("fetched/processed %s email(s) on %s server %s", count, server.type, server.name) _logger.info("Fetched %d email(s) on %s server %s; %d succeeded, %d failed.", count, server.type, server.name, (count - failed), failed)
except Exception: except Exception:
_logger.exception("Failed to fetch mail from %s server %s.", server.type, server.name) _logger.exception("General failure when trying to fetch mail from %s server %s.", server.type, server.name)
finally: finally:
if imap_server: if imap_server:
imap_server.close() imap_server.close()
@ -222,18 +228,23 @@ openerp_mailgate: "|/path/to/openerp-mailgate.py --host=localhost -u %(uid)d -p
for num in range(1, numMsgs + 1): for num in range(1, numMsgs + 1):
(header, msges, octets) = pop_server.retr(num) (header, msges, octets) = pop_server.retr(num)
msg = '\n'.join(msges) msg = '\n'.join(msges)
res_id = mail_thread.message_process(cr, uid, server.object_id.model, res_id = None
msg, try:
save_original=server.original, res_id = mail_thread.message_process(cr, uid, server.object_id.model,
strip_attachments=(not server.attach), msg,
context=context) save_original=server.original,
strip_attachments=(not server.attach),
context=context)
except Exception:
_logger.exception('Failed to process mail from %s server %s.', server.type, server.name)
failed += 1
if res_id and server.action_id: if res_id and server.action_id:
action_pool.run(cr, uid, [server.action_id.id], {'active_id': res_id, 'active_ids':[res_id], 'active_model': context.get("thread_model", server.object_id.model)}) action_pool.run(cr, uid, [server.action_id.id], {'active_id': res_id, 'active_ids': [res_id], 'active_model': context.get("thread_model", server.object_id.model)})
pop_server.dele(num) pop_server.dele(num)
cr.commit() cr.commit()
_logger.info("fetched/processed %s email(s) on %s server %s", numMsgs, server.type, server.name) _logger.info("Fetched %d email(s) on %s server %s; %d succeeded, %d failed.", numMsgs, server.type, server.name, (numMsgs - failed), failed)
except Exception: except Exception:
_logger.exception("Failed to fetch mail from %s server %s.", server.type, server.name) _logger.exception("General failure when trying to fetch mail from %s server %s.", server.type, server.name)
finally: finally:
if pop_server: if pop_server:
pop_server.quit() pop_server.quit()

View File

@ -708,13 +708,15 @@ class mail_thread(osv.AbstractModel):
# Private message: should not contain any thread_id # Private message: should not contain any thread_id
if not model and thread_id: if not model and thread_id:
if assert_model: if assert_model:
assert thread_id == 0, 'Routing: posting a message without model should be with a null res_id (private message).' if thread_id:
raise ValueError('Routing: posting a message without model should be with a null res_id (private message).')
_warn('posting a message without model should be with a null res_id (private message), resetting thread_id') _warn('posting a message without model should be with a null res_id (private message), resetting thread_id')
thread_id = 0 thread_id = 0
# Private message: should have a parent_id (only answers) # Private message: should have a parent_id (only answers)
if not model and not message_dict.get('parent_id'): if not model and not message_dict.get('parent_id'):
if assert_model: if assert_model:
assert message_dict.get('parent_id'), 'Routing: posting a message without model should be with a parent_id (private mesage).' if not message_dict.get('parent_id'):
raise ValueError('Routing: posting a message without model should be with a parent_id (private mesage).')
_warn('posting a message without model should be with a parent_id (private mesage), skipping') _warn('posting a message without model should be with a parent_id (private mesage), skipping')
return () return ()
@ -743,7 +745,10 @@ class mail_thread(osv.AbstractModel):
# New Document: check model accepts the mailgateway # New Document: check model accepts the mailgateway
if not thread_id and model and not hasattr(model_pool, 'message_new'): if not thread_id and model and not hasattr(model_pool, 'message_new'):
if assert_model: if assert_model:
assert hasattr(model_pool, 'message_new'), 'Model %s does not accept document creation, crashing' % model if not hasattr(model_pool, 'message_new'):
raise ValueError(
'Model %s does not accept document creation, crashing' % model
)
_warn('model %s does not accept document creation, skipping' % model) _warn('model %s does not accept document creation, skipping' % model)
return () return ()
@ -804,8 +809,11 @@ class mail_thread(osv.AbstractModel):
to which this mail should be attached. Only used if the message to which this mail should be attached. Only used if the message
does not reply to an existing thread and does not match any mail alias. does not reply to an existing thread and does not match any mail alias.
:return: list of [model, thread_id, custom_values, user_id, alias] :return: list of [model, thread_id, custom_values, user_id, alias]
:raises: ValueError, TypeError
""" """
assert isinstance(message, Message), 'message must be an email.message.Message at this point' if not isinstance(message, Message):
raise TypeError('message must be an email.message.Message at this point')
fallback_model = model fallback_model = model
# Get email.message.Message variables for future processing # Get email.message.Message variables for future processing
@ -899,9 +907,11 @@ class mail_thread(osv.AbstractModel):
return [route] return [route]
# AssertionError if no routes found and if no bounce occured # AssertionError if no routes found and if no bounce occured
assert False, \ raise ValueError(
"No possible route found for incoming message from %s to %s (Message-Id %s:)." \ 'No possible route found for incoming message from %s to %s (Message-Id %s:). '
"Create an appropriate mail.alias or force the destination model." % (email_from, email_to, message_id) 'Create an appropriate mail.alias or force the destination model.' %
(email_from, email_to, message_id)
)
def message_route_process(self, cr, uid, message, message_dict, routes, context=None): def message_route_process(self, cr, uid, message, message_dict, routes, context=None):
# postpone setting message_dict.partner_ids after message_post, to avoid double notifications # postpone setting message_dict.partner_ids after message_post, to avoid double notifications
@ -912,9 +922,11 @@ class mail_thread(osv.AbstractModel):
context.update({'thread_model': model}) context.update({'thread_model': model})
if model: if model:
model_pool = self.pool[model] model_pool = self.pool[model]
assert thread_id and hasattr(model_pool, 'message_update') or hasattr(model_pool, 'message_new'), \ if not (thread_id and hasattr(model_pool, 'message_update') or hasattr(model_pool, 'message_new')):
"Undeliverable mail with Message-Id %s, model %s does not accept incoming emails" % \ raise ValueError(
(message_dict['message_id'], model) "Undeliverable mail with Message-Id %s, model %s does not accept incoming emails" %
(message_dict['message_id'], model)
)
# disabled subscriptions during message_new/update to avoid having the system user running the # disabled subscriptions during message_new/update to avoid having the system user running the
# email gateway become a follower of all inbound messages # email gateway become a follower of all inbound messages
@ -924,7 +936,8 @@ class mail_thread(osv.AbstractModel):
else: else:
thread_id = model_pool.message_new(cr, user_id, message_dict, custom_values, context=nosub_ctx) thread_id = model_pool.message_new(cr, user_id, message_dict, custom_values, context=nosub_ctx)
else: else:
assert thread_id == 0, "Posting a message without model should be with a null res_id, to create a private message." if thread_id:
raise ValueError("Posting a message without model should be with a null res_id, to create a private message.")
model_pool = self.pool.get('mail.thread') model_pool = self.pool.get('mail.thread')
if not hasattr(model_pool, 'message_post'): if not hasattr(model_pool, 'message_post'):
context['thread_model'] = model context['thread_model'] = model

View File

@ -117,6 +117,9 @@
.openerp .oe_mail .oe_msg .oe_msg_content .oe_msg_body p { .openerp .oe_mail .oe_msg .oe_msg_content .oe_msg_body p {
margin-bottom: 0px; margin-bottom: 0px;
} }
.openerp .oe_mail .oe_msg .oe_msg_content .oe_msg_body pre {
white-space: pre-wrap;
}
.openerp .oe_mail .oe_msg .oe_msg_content .oe_msg_body * { .openerp .oe_mail .oe_msg .oe_msg_content .oe_msg_body * {
text-overflow:ellipsis; text-overflow:ellipsis;
word-wrap: break-word; word-wrap: break-word;

View File

@ -465,14 +465,14 @@ class TestMailgateway(TestMail):
# -------------------------------------------------- # --------------------------------------------------
# Do: incoming email with model that does not accepts incoming emails must raise # Do: incoming email with model that does not accepts incoming emails must raise
self.assertRaises(AssertionError, self.assertRaises(ValueError,
format_and_process, format_and_process,
MAIL_TEMPLATE, MAIL_TEMPLATE,
to='noone@example.com', subject='spam', extra='', model='res.country', to='noone@example.com', subject='spam', extra='', model='res.country',
msg_id='<1198923581.41972151344608186760.JavaMail.new4@agrolait.com>') msg_id='<1198923581.41972151344608186760.JavaMail.new4@agrolait.com>')
# Do: incoming email without model and without alias must raise # Do: incoming email without model and without alias must raise
self.assertRaises(AssertionError, self.assertRaises(ValueError,
format_and_process, format_and_process,
MAIL_TEMPLATE, MAIL_TEMPLATE,
to='noone@example.com', subject='spam', extra='', to='noone@example.com', subject='spam', extra='',