[MERGE] forward port of branch saas-4 up to 65f68c1
This commit is contained in:
+3
-1
@@ -3,6 +3,7 @@ _build/
|
|||||||
|
|
||||||
# dotfiles
|
# dotfiles
|
||||||
.*
|
.*
|
||||||
|
!.gitignore
|
||||||
# compiled python files
|
# compiled python files
|
||||||
*.py[co]
|
*.py[co]
|
||||||
# setup.py egg_info
|
# setup.py egg_info
|
||||||
@@ -12,7 +13,8 @@ _build/
|
|||||||
# hg stuff
|
# hg stuff
|
||||||
*.orig
|
*.orig
|
||||||
status
|
status
|
||||||
|
# odoo filestore
|
||||||
|
openerp/filestore
|
||||||
# generated for windows installer?
|
# generated for windows installer?
|
||||||
install/win32/*.bat
|
install/win32/*.bat
|
||||||
install/win32/meta.py
|
install/win32/meta.py
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ class sale_order(osv.Model):
|
|||||||
if not grid_id:
|
if not grid_id:
|
||||||
raise osv.except_osv(_('No Grid Available!'), _('No grid matching for this carrier!'))
|
raise osv.except_osv(_('No Grid Available!'), _('No grid matching for this carrier!'))
|
||||||
|
|
||||||
if order.state != 'draft':
|
if order.state not in ('draft', 'sent'):
|
||||||
raise osv.except_osv(_('Order not in Draft State!'), _('The order state have to be draft to add delivery lines.'))
|
raise osv.except_osv(_('Order not in Draft State!'), _('The order state have to be draft to add delivery lines.'))
|
||||||
|
|
||||||
grid = grid_obj.browse(cr, uid, grid_id, context=context)
|
grid = grid_obj.browse(cr, uid, grid_id, context=context)
|
||||||
|
|||||||
@@ -39,16 +39,15 @@ instance.edi.EdiImport = instance.web.Widget.extend({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$('<div>').dialog({
|
new instance.web.Dialog(this,{
|
||||||
modal: true,
|
title: 'Import Successful!',
|
||||||
title: 'Import Successful!',
|
buttons: {
|
||||||
buttons: {
|
Ok: function() {
|
||||||
Ok: function() {
|
this.parents('.modal').modal('hide');
|
||||||
$(this).dialog("close");
|
window.location = "/";
|
||||||
window.location = "/";
|
}
|
||||||
}
|
}
|
||||||
}
|
},$('<div>').html(_t('The document has been successfully imported!'))).open();
|
||||||
}).html(_t('The document has been successfully imported!'));
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
on_imported_error: function(response){
|
on_imported_error: function(response){
|
||||||
@@ -58,13 +57,12 @@ instance.edi.EdiImport = instance.web.Widget.extend({
|
|||||||
msg += "\n " + _t("Reason:") + response.data.message;
|
msg += "\n " + _t("Reason:") + response.data.message;
|
||||||
}
|
}
|
||||||
var params = {error: response, message: msg};
|
var params = {error: response, message: msg};
|
||||||
$(instance.web.qweb.render("CrashManager.warning", params)).dialog({
|
new instance.web.Dialog(this,{
|
||||||
title: _t("Document Import Notification"),
|
title: _t("Document Import Notification"),
|
||||||
modal: true,
|
buttons: {
|
||||||
buttons: {
|
Ok: function() { this.parents('.modal').modal('hide');}
|
||||||
Ok: function() { $(this).dialog("close"); }
|
}
|
||||||
}
|
},$(instance.web.qweb.render("CrashManager.warning", params))).open();
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -159,7 +159,11 @@ class event_event(osv.osv):
|
|||||||
help="The maximum registration level is equal to the sum of the maximum registration of event ticket." +
|
help="The maximum registration level is equal to the sum of the maximum registration of event ticket." +
|
||||||
"If you have too much registrations you are not able to confirm your event. (0 to ignore this rule )",
|
"If you have too much registrations you are not able to confirm your event. (0 to ignore this rule )",
|
||||||
type='integer',
|
type='integer',
|
||||||
readonly=True),
|
readonly=True,
|
||||||
|
store={
|
||||||
|
'event.event': (lambda self, cr, uid, ids, c = {}: ids, ['event_ticket_ids'], 20),
|
||||||
|
'event.event.ticket': (_get_ticket_events, ['seats_max'], 10),
|
||||||
|
}),
|
||||||
'seats_available': fields.function(Event._get_seats, oldname='register_avail', string='Available Seats',
|
'seats_available': fields.function(Event._get_seats, oldname='register_avail', string='Available Seats',
|
||||||
type='integer', multi='seats_reserved',
|
type='integer', multi='seats_reserved',
|
||||||
store={
|
store={
|
||||||
|
|||||||
@@ -333,7 +333,8 @@ class gamification_goal(osv.Model):
|
|||||||
|
|
||||||
if definition.computation_mode == 'sum':
|
if definition.computation_mode == 'sum':
|
||||||
field_name = definition.field_id.name
|
field_name = definition.field_id.name
|
||||||
res = obj.read_group(cr, uid, domain, [field_name], [field_name], context=context)
|
# TODO for master: group on user field in batch mode
|
||||||
|
res = obj.read_group(cr, uid, domain, [field_name], [], context=context)
|
||||||
new_value = res and res[0][field_name] or 0.0
|
new_value = res and res[0][field_name] or 0.0
|
||||||
|
|
||||||
else: # computation mode = count
|
else: # computation mode = count
|
||||||
|
|||||||
+20
-10
@@ -889,9 +889,10 @@ class mail_thread(osv.AbstractModel):
|
|||||||
thread_references = references or in_reply_to
|
thread_references = references or in_reply_to
|
||||||
|
|
||||||
# 1. message is a reply to an existing message (exact match of message_id)
|
# 1. message is a reply to an existing message (exact match of message_id)
|
||||||
|
ref_match = thread_references and tools.reference_re.search(thread_references)
|
||||||
msg_references = thread_references.split()
|
msg_references = thread_references.split()
|
||||||
mail_message_ids = mail_msg_obj.search(cr, uid, [('message_id', 'in', msg_references)], context=context)
|
mail_message_ids = mail_msg_obj.search(cr, uid, [('message_id', 'in', msg_references)], context=context)
|
||||||
if mail_message_ids:
|
if ref_match and mail_message_ids:
|
||||||
original_msg = mail_msg_obj.browse(cr, SUPERUSER_ID, mail_message_ids[0], context=context)
|
original_msg = mail_msg_obj.browse(cr, SUPERUSER_ID, mail_message_ids[0], context=context)
|
||||||
model, thread_id = original_msg.model, original_msg.res_id
|
model, thread_id = original_msg.model, original_msg.res_id
|
||||||
route = self.message_route_verify(
|
route = self.message_route_verify(
|
||||||
@@ -905,7 +906,6 @@ class mail_thread(osv.AbstractModel):
|
|||||||
return [route]
|
return [route]
|
||||||
|
|
||||||
# 2. message is a reply to an existign thread (6.1 compatibility)
|
# 2. message is a reply to an existign thread (6.1 compatibility)
|
||||||
ref_match = thread_references and tools.reference_re.search(thread_references)
|
|
||||||
if ref_match:
|
if ref_match:
|
||||||
reply_thread_id = int(ref_match.group(1))
|
reply_thread_id = int(ref_match.group(1))
|
||||||
reply_model = ref_match.group(2) or fallback_model
|
reply_model = ref_match.group(2) or fallback_model
|
||||||
@@ -945,8 +945,9 @@ class mail_thread(osv.AbstractModel):
|
|||||||
(mail_message.model, mail_message.res_id, custom_values, uid, None),
|
(mail_message.model, mail_message.res_id, custom_values, uid, None),
|
||||||
update_author=True, assert_model=True, create_fallback=True, allow_private=True, context=context)
|
update_author=True, assert_model=True, create_fallback=True, allow_private=True, context=context)
|
||||||
if route:
|
if route:
|
||||||
_logger.info('Routing mail from %s to %s with Message-Id %s: direct reply to a private message: %s, custom_values: %s, uid: %s',
|
_logger.info(
|
||||||
email_from, email_to, message_id, mail_message.id, custom_values, uid)
|
'Routing mail from %s to %s with Message-Id %s: direct reply to a private message: %s, custom_values: %s, uid: %s',
|
||||||
|
email_from, email_to, message_id, mail_message.id, custom_values, uid)
|
||||||
return [route]
|
return [route]
|
||||||
|
|
||||||
# 3. Look for a matching mail.alias entry
|
# 3. Look for a matching mail.alias entry
|
||||||
@@ -975,11 +976,12 @@ class mail_thread(osv.AbstractModel):
|
|||||||
user_id = uid
|
user_id = uid
|
||||||
_logger.info('No matching user_id for the alias %s', alias.alias_name)
|
_logger.info('No matching user_id for the alias %s', alias.alias_name)
|
||||||
route = (alias.alias_model_id.model, alias.alias_force_thread_id, eval(alias.alias_defaults), user_id, alias)
|
route = (alias.alias_model_id.model, alias.alias_force_thread_id, eval(alias.alias_defaults), user_id, alias)
|
||||||
_logger.info('Routing mail from %s to %s with Message-Id %s: direct alias match: %r',
|
|
||||||
email_from, email_to, message_id, route)
|
|
||||||
route = self.message_route_verify(cr, uid, message, message_dict, route,
|
route = self.message_route_verify(cr, uid, message, message_dict, route,
|
||||||
update_author=True, assert_model=True, create_fallback=True, context=context)
|
update_author=True, assert_model=True, create_fallback=True, context=context)
|
||||||
if route:
|
if route:
|
||||||
|
_logger.info(
|
||||||
|
'Routing mail from %s to %s with Message-Id %s: direct alias match: %r',
|
||||||
|
email_from, email_to, message_id, route)
|
||||||
routes.append(route)
|
routes.append(route)
|
||||||
return routes
|
return routes
|
||||||
|
|
||||||
@@ -993,15 +995,16 @@ class mail_thread(osv.AbstractModel):
|
|||||||
thread_id = int(thread_id)
|
thread_id = int(thread_id)
|
||||||
except:
|
except:
|
||||||
thread_id = False
|
thread_id = False
|
||||||
_logger.info('Routing mail from %s to %s with Message-Id %s: fallback to model:%s, thread_id:%s, custom_values:%s, uid:%s',
|
|
||||||
email_from, email_to, message_id, fallback_model, thread_id, custom_values, uid)
|
|
||||||
route = self.message_route_verify(cr, uid, message, message_dict,
|
route = self.message_route_verify(cr, uid, message, message_dict,
|
||||||
(fallback_model, thread_id, custom_values, uid, None),
|
(fallback_model, thread_id, custom_values, uid, None),
|
||||||
update_author=True, assert_model=True, context=context)
|
update_author=True, assert_model=True, context=context)
|
||||||
if route:
|
if route:
|
||||||
|
_logger.info(
|
||||||
|
'Routing mail from %s to %s with Message-Id %s: fallback to model:%s, thread_id:%s, custom_values:%s, uid:%s',
|
||||||
|
email_from, email_to, message_id, fallback_model, thread_id, custom_values, uid)
|
||||||
return [route]
|
return [route]
|
||||||
|
|
||||||
# AssertionError if no routes found and if no bounce occured
|
# ValueError if no routes found and if no bounce occured
|
||||||
raise ValueError(
|
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.' %
|
'Create an appropriate mail.alias or force the destination model.' %
|
||||||
@@ -1171,7 +1174,14 @@ class mail_thread(osv.AbstractModel):
|
|||||||
body = u''
|
body = u''
|
||||||
if save_original:
|
if save_original:
|
||||||
attachments.append(('original_email.eml', message.as_string()))
|
attachments.append(('original_email.eml', message.as_string()))
|
||||||
if not message.is_multipart() or 'text/' in message.get('content-type', ''):
|
|
||||||
|
# Be careful, content-type may contain tricky content like in the
|
||||||
|
# following example so test the MIME type with startswith()
|
||||||
|
#
|
||||||
|
# Content-Type: multipart/related;
|
||||||
|
# boundary="_004_3f1e4da175f349248b8d43cdeb9866f1AMSPR06MB343eurprd06pro_";
|
||||||
|
# type="text/html"
|
||||||
|
if not message.is_multipart() or message.get('content-type', '').startswith("text/"):
|
||||||
encoding = message.get_content_charset()
|
encoding = message.get_content_charset()
|
||||||
body = message.get_payload(decode=True)
|
body = message.get_payload(decode=True)
|
||||||
body = tools.ustr(body, encoding, errors='replace')
|
body = tools.ustr(body, encoding, errors='replace')
|
||||||
|
|||||||
@@ -43,10 +43,15 @@ class MailComposeMessage(osv.TransientModel):
|
|||||||
}, context=context)
|
}, context=context)
|
||||||
mass_mailing = self.pool['mail.mass_mailing'].browse(cr, uid, mass_mailing_id, context=context)
|
mass_mailing = self.pool['mail.mass_mailing'].browse(cr, uid, mass_mailing_id, context=context)
|
||||||
for res_id in res_ids:
|
for res_id in res_ids:
|
||||||
res[res_id]['mailing_id'] = mass_mailing.id
|
res[res_id].update({
|
||||||
res[res_id]['statistics_ids'] = [(0, 0, {
|
'mailing_id': mass_mailing.id,
|
||||||
'model': wizard.model,
|
'statistics_ids': [(0, 0, {
|
||||||
'res_id': res_id,
|
'model': wizard.model,
|
||||||
'mass_mailing_id': mass_mailing.id,
|
'res_id': res_id,
|
||||||
})]
|
'mass_mailing_id': mass_mailing.id,
|
||||||
|
})],
|
||||||
|
# email-mode: keep original message for routing
|
||||||
|
'notification': mass_mailing.reply_to_mode == 'thread',
|
||||||
|
'auto_delete': True,
|
||||||
|
})
|
||||||
return res
|
return res
|
||||||
|
|||||||
@@ -661,6 +661,8 @@ class purchase_order(osv.osv):
|
|||||||
_('You must first cancel all invoices related to this purchase order.'))
|
_('You must first cancel all invoices related to this purchase order.'))
|
||||||
self.pool.get('account.invoice') \
|
self.pool.get('account.invoice') \
|
||||||
.signal_invoice_cancel(cr, uid, map(attrgetter('id'), purchase.invoice_ids))
|
.signal_invoice_cancel(cr, uid, map(attrgetter('id'), purchase.invoice_ids))
|
||||||
|
self.pool['purchase.order.line'].write(cr, uid, [l.id for l in purchase.order_line],
|
||||||
|
{'state': 'cancel'})
|
||||||
self.write(cr, uid, ids, {'state': 'cancel'})
|
self.write(cr, uid, ids, {'state': 'cancel'})
|
||||||
self.set_order_line_status(cr, uid, ids, 'cancel', context=context)
|
self.set_order_line_status(cr, uid, ids, 'cancel', context=context)
|
||||||
self.signal_purchase_cancel(cr, uid, ids)
|
self.signal_purchase_cancel(cr, uid, ids)
|
||||||
@@ -982,6 +984,9 @@ class purchase_order_line(osv.osv):
|
|||||||
return super(purchase_order_line, self).copy_data(cr, uid, id, default, context)
|
return super(purchase_order_line, self).copy_data(cr, uid, id, default, context)
|
||||||
|
|
||||||
def unlink(self, cr, uid, ids, context=None):
|
def unlink(self, cr, uid, ids, context=None):
|
||||||
|
for line in self.browse(cr, uid, ids, context=context):
|
||||||
|
if line.state not in ['draft', 'cancel']:
|
||||||
|
raise osv.except_osv(_('Invalid Action!'), _('Cannot delete a purchase order line which is in state \'%s\'.') %(line.state,))
|
||||||
procurement_obj = self.pool.get('procurement.order')
|
procurement_obj = self.pool.get('procurement.order')
|
||||||
procurement_ids_to_cancel = procurement_obj.search(cr, uid, [('purchase_line_id', 'in', ids)], context=context)
|
procurement_ids_to_cancel = procurement_obj.search(cr, uid, [('purchase_line_id', 'in', ids)], context=context)
|
||||||
if procurement_ids_to_cancel:
|
if procurement_ids_to_cancel:
|
||||||
|
|||||||
+7
-3
@@ -538,14 +538,18 @@ class sale_order(osv.osv):
|
|||||||
if grouped:
|
if grouped:
|
||||||
res = self._make_invoice(cr, uid, val[0][0], reduce(lambda x, y: x + y, [l for o, l in val], []), context=context)
|
res = self._make_invoice(cr, uid, val[0][0], reduce(lambda x, y: x + y, [l for o, l in val], []), context=context)
|
||||||
invoice_ref = ''
|
invoice_ref = ''
|
||||||
|
origin_ref = ''
|
||||||
for o, l in val:
|
for o, l in val:
|
||||||
invoice_ref += o.name + '|'
|
invoice_ref += (o.client_order_ref or o.name) + '|'
|
||||||
|
origin_ref += (o.origin or o.name) + '|'
|
||||||
self.write(cr, uid, [o.id], {'state': 'progress'})
|
self.write(cr, uid, [o.id], {'state': 'progress'})
|
||||||
cr.execute('insert into sale_order_invoice_rel (order_id,invoice_id) values (%s,%s)', (o.id, res))
|
cr.execute('insert into sale_order_invoice_rel (order_id,invoice_id) values (%s,%s)', (o.id, res))
|
||||||
#remove last '|' in invoice_ref
|
#remove last '|' in invoice_ref
|
||||||
if len(invoice_ref) >= 1:
|
if len(invoice_ref) >= 1:
|
||||||
invoice_ref = invoice_ref[:-1]
|
invoice_ref = invoice_ref[:-1]
|
||||||
invoice.write(cr, uid, [res], {'origin': invoice_ref, 'name': invoice_ref})
|
if len(origin_ref) >= 1:
|
||||||
|
origin_ref = origin_ref[:-1]
|
||||||
|
invoice.write(cr, uid, [res], {'origin': origin_ref, 'name': invoice_ref})
|
||||||
else:
|
else:
|
||||||
for order, il in val:
|
for order, il in val:
|
||||||
res = self._make_invoice(cr, uid, order, il, context=context)
|
res = self._make_invoice(cr, uid, order, il, context=context)
|
||||||
|
|||||||
@@ -2276,6 +2276,9 @@ class stock_move(osv.osv):
|
|||||||
|
|
||||||
#Check moves that were pushed
|
#Check moves that were pushed
|
||||||
if move.move_dest_id.state in ('waiting', 'confirmed'):
|
if move.move_dest_id.state in ('waiting', 'confirmed'):
|
||||||
|
# FIXME is opw 607970 still present with new WMS?
|
||||||
|
# (see commits 1ef2c181033bd200906fb1e5ce35e234bf566ac6
|
||||||
|
# and 41c5ceb8ebb95c1b4e98d8dd1f12b8e547a24b1d)
|
||||||
other_upstream_move_ids = self.search(cr, uid, [('id', '!=', move.id), ('state', 'not in', ['done', 'cancel']),
|
other_upstream_move_ids = self.search(cr, uid, [('id', '!=', move.id), ('state', 'not in', ['done', 'cancel']),
|
||||||
('move_dest_id', '=', move.move_dest_id.id)], context=context)
|
('move_dest_id', '=', move.move_dest_id.id)], context=context)
|
||||||
#If no other moves for the move that got pushed:
|
#If no other moves for the move that got pushed:
|
||||||
|
|||||||
@@ -779,9 +779,9 @@ instance.web_kanban.KanbanGroup = instance.web.Widget.extend({
|
|||||||
});
|
});
|
||||||
var am = instance.webclient.action_manager;
|
var am = instance.webclient.action_manager;
|
||||||
var form = am.dialog_widget.views.form.controller;
|
var form = am.dialog_widget.views.form.controller;
|
||||||
form.on("on_button_cancel", am.dialog, am.dialog.close);
|
form.on("on_button_cancel", am.dialog, function() { return am.dialog.$dialog_box.modal('hide'); });
|
||||||
form.on('record_saved', self, function() {
|
form.on('record_saved', self, function() {
|
||||||
am.dialog.close();
|
am.dialog.$dialog_box.modal('hide');
|
||||||
self.view.do_reload();
|
self.view.do_reload();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -108,6 +108,7 @@
|
|||||||
"access_multi_company_default manager","multi_company_default Manager","model_multi_company_default","group_erp_manager",1,1,1,1
|
"access_multi_company_default manager","multi_company_default Manager","model_multi_company_default","group_erp_manager",1,1,1,1
|
||||||
"access_ir_filter all","ir_filters all","model_ir_filters",,1,1,1,1
|
"access_ir_filter all","ir_filters all","model_ir_filters",,1,1,1,1
|
||||||
"access_ir_config_parameter","ir_config_parameter","model_ir_config_parameter",,1,0,0,0
|
"access_ir_config_parameter","ir_config_parameter","model_ir_config_parameter",,1,0,0,0
|
||||||
|
"access_ir_config_parameter_system","ir_config_parameter_system","model_ir_config_parameter","group_system",1,1,1,1
|
||||||
"access_ir_mail_server","ir_mail_server","model_ir_mail_server","group_system",1,1,1,1
|
"access_ir_mail_server","ir_mail_server","model_ir_mail_server","group_system",1,1,1,1
|
||||||
"access_ir_actions_client","ir_actions_client all","model_ir_actions_client",,1,0,0,0
|
"access_ir_actions_client","ir_actions_client all","model_ir_actions_client",,1,0,0,0
|
||||||
"access_ir_needaction_mixin","ir_needaction_mixin","model_ir_needaction_mixin",,1,1,1,1
|
"access_ir_needaction_mixin","ir_needaction_mixin","model_ir_needaction_mixin",,1,1,1,1
|
||||||
|
|||||||
|
+1
-1
@@ -2449,7 +2449,7 @@ class BaseModel(object):
|
|||||||
fetched_data = cr.dictfetchall()
|
fetched_data = cr.dictfetchall()
|
||||||
|
|
||||||
if not groupby_fields:
|
if not groupby_fields:
|
||||||
return {r.pop('id'): r for r in fetched_data}
|
return fetched_data
|
||||||
|
|
||||||
many2onefields = [gb['field'] for gb in annotated_groupbys if gb['type'] == 'many2one']
|
many2onefields = [gb['field'] for gb in annotated_groupbys if gb['type'] == 'many2one']
|
||||||
if many2onefields:
|
if many2onefields:
|
||||||
|
|||||||
Reference in New Issue
Block a user