diff --git a/addons/base_address_extended/models/base_address_extended.py b/addons/base_address_extended/models/base_address_extended.py
index 566f2cb40f9..85aa0a6dddf 100644
--- a/addons/base_address_extended/models/base_address_extended.py
+++ b/addons/base_address_extended/models/base_address_extended.py
@@ -91,7 +91,7 @@ class Partner(models.Model):
for partner in self:
if not partner.street:
for field in street_fields:
- partner[field] = ''
+ partner[field] = None
continue
street_format = (partner.country_id.street_format or
diff --git a/addons/base_import/models/base_import.py b/addons/base_import/models/base_import.py
index 6a2f6b729bc..d700753a934 100644
--- a/addons/base_import/models/base_import.py
+++ b/addons/base_import/models/base_import.py
@@ -305,6 +305,8 @@ class Import(models.TransientModel):
if all(val.lower() in ('true', 'false', 't', 'f', '') for val in preview_values):
return ['boolean']
# If all values can be cast to float, type is either float or monetary
+ # Or a date/datetime if it matches the pattern
+ results = []
try:
thousand_separator = decimal_separator = False
for val in preview_values:
@@ -336,7 +338,7 @@ class Import(models.TransientModel):
if thousand_separator and not options.get('float_decimal_separator'):
options['float_thousand_separator'] = thousand_separator
options['float_decimal_separator'] = decimal_separator
- return ['float', 'monetary']
+ results = ['float', 'monetary']
except ValueError:
pass
# Try to see if all values are a date or datetime
@@ -372,13 +374,15 @@ class Import(models.TransientModel):
current_date_pattern = check_patterns(date_patterns, preview_values)
if current_date_pattern:
options['date_format'] = current_date_pattern
- return ['date']
+ results += ['date']
current_datetime_pattern = check_patterns(datetime_patterns, preview_values)
if current_datetime_pattern:
options['datetime_format'] = current_datetime_pattern
- return ['datetime']
+ results += ['datetime']
+ if results:
+ return results
return ['text', 'char', 'datetime', 'selection', 'many2one', 'one2many', 'many2many', 'html']
@api.model
@@ -500,7 +504,7 @@ class Import(models.TransientModel):
'headers_type': header_types or False,
'preview': preview,
'options': options,
- 'advanced_mode': any([len(models.fix_import_export_id_paths(col)) > 1 for col in headers]),
+ 'advanced_mode': any([len(models.fix_import_export_id_paths(col)) > 1 for col in headers or []]),
'debug': self.user_has_groups('base.group_no_one'),
}
except Exception, error:
diff --git a/addons/delivery/models/delivery_carrier.py b/addons/delivery/models/delivery_carrier.py
index dc91bf4e5e6..b631bdd1429 100644
--- a/addons/delivery/models/delivery_carrier.py
+++ b/addons/delivery/models/delivery_carrier.py
@@ -201,9 +201,9 @@ class DeliveryCarrier(models.Model):
return False
if self.state_ids and contact.state_id not in self.state_ids:
return False
- if self.zip_from and (contact.zip or '') < self.zip_from:
+ if self.zip_from and (contact.zip or '').upper() < self.zip_from.upper():
return False
- if self.zip_to and (contact.zip or '') > self.zip_to:
+ if self.zip_to and (contact.zip or '').upper() > self.zip_to.upper():
return False
return self
diff --git a/addons/im_livechat/controllers/main.py b/addons/im_livechat/controllers/main.py
index f033fc72cc7..030581e12f2 100644
--- a/addons/im_livechat/controllers/main.py
+++ b/addons/im_livechat/controllers/main.py
@@ -75,7 +75,7 @@ class LivechatController(http.Controller):
# if the user is identifiy (eg: portal user on the frontend), don't use the anonymous name. The user will be added to session.
if request.session.uid:
anonymous_name = request.env.user.name
- return request.env["im_livechat.channel"].get_mail_channel(channel_id, anonymous_name)
+ return request.env["im_livechat.channel"].with_context(lang=False).get_mail_channel(channel_id, anonymous_name)
@http.route('/im_livechat/feedback', type='json', auth='public')
def feedback(self, uuid, rate, reason=None, **kwargs):
diff --git a/addons/mrp/models/mrp_unbuild.py b/addons/mrp/models/mrp_unbuild.py
index 31cd5226346..09fdabc4b18 100644
--- a/addons/mrp/models/mrp_unbuild.py
+++ b/addons/mrp/models/mrp_unbuild.py
@@ -106,6 +106,8 @@ class MrpUnbuild(models.Model):
self.env['stock.quant'].quants_reserve(quants, consume_move)
if consume_move.has_tracking != 'none':
+ if not quants[0][0]:
+ raise UserError(_("You don't have in the stock the lot %s.") % (self.lot_id.name,))
self.env['stock.move.lots'].create({
'move_id': consume_move.id,
'lot_id': self.lot_id.id,
@@ -119,6 +121,8 @@ class MrpUnbuild(models.Model):
for produce_move in produce_moves:
if produce_move.has_tracking != 'none':
original = original_quants.filtered(lambda quant: quant.product_id == produce_move.product_id)
+ if not original.lot_id:
+ raise UserError(_("You don't have in the stock the required lot/serial number for %s .") % (produce_move.product_id.name,))
self.env['stock.move.lots'].create({
'move_id': produce_move.id,
'lot_id': original.lot_id.id,
diff --git a/addons/mrp_repair/models/mrp_repair.py b/addons/mrp_repair/models/mrp_repair.py
index e8d362ae67c..6e0f188c6b2 100644
--- a/addons/mrp_repair/models/mrp_repair.py
+++ b/addons/mrp_repair/models/mrp_repair.py
@@ -15,7 +15,7 @@ class Repair(models.Model):
@api.model
def _default_stock_location(self):
- warehouse = self.env.ref('stock.warehouse0', raise_if_not_found=False)
+ warehouse = self.env['stock.warehouse'].search([], limit=1)
if warehouse:
return warehouse.lot_stock_id.id
return False
diff --git a/addons/stock/models/product.py b/addons/stock/models/product.py
index 11d89207ada..f7f0ab75d32 100644
--- a/addons/stock/models/product.py
+++ b/addons/stock/models/product.py
@@ -143,15 +143,15 @@ class Product(models.Model):
Quant = self.env['stock.quant']
domain_move_in_todo = [('state', 'not in', ('done', 'cancel', 'draft'))] + domain_move_in
domain_move_out_todo = [('state', 'not in', ('done', 'cancel', 'draft'))] + domain_move_out
- moves_in_res = dict((item['product_id'][0], item['product_qty']) for item in Move.read_group(domain_move_in_todo, ['product_id', 'product_qty'], ['product_id']))
- moves_out_res = dict((item['product_id'][0], item['product_qty']) for item in Move.read_group(domain_move_out_todo, ['product_id', 'product_qty'], ['product_id']))
- quants_res = dict((item['product_id'][0], item['qty']) for item in Quant.read_group(domain_quant, ['product_id', 'qty'], ['product_id']))
+ moves_in_res = dict((item['product_id'][0], item['product_qty']) for item in Move.read_group(domain_move_in_todo, ['product_id', 'product_qty'], ['product_id'], orderby='id'))
+ moves_out_res = dict((item['product_id'][0], item['product_qty']) for item in Move.read_group(domain_move_out_todo, ['product_id', 'product_qty'], ['product_id'], orderby='id'))
+ quants_res = dict((item['product_id'][0], item['qty']) for item in Quant.read_group(domain_quant, ['product_id', 'qty'], ['product_id'], orderby='id'))
if dates_in_the_past:
# Calculate the moves that were done before now to calculate back in time (as most questions will be recent ones)
domain_move_in_done = [('state', '=', 'done'), ('date', '>', to_date)] + domain_move_in_done
domain_move_out_done = [('state', '=', 'done'), ('date', '>', to_date)] + domain_move_out_done
- moves_in_res_past = dict((item['product_id'][0], item['product_qty']) for item in Move.read_group(domain_move_in_done, ['product_id', 'product_qty'], ['product_id']))
- moves_out_res_past = dict((item['product_id'][0], item['product_qty']) for item in Move.read_group(domain_move_out_done, ['product_id', 'product_qty'], ['product_id']))
+ moves_in_res_past = dict((item['product_id'][0], item['product_qty']) for item in Move.read_group(domain_move_in_done, ['product_id', 'product_qty'], ['product_id'], orderby='id'))
+ moves_out_res_past = dict((item['product_id'][0], item['product_qty']) for item in Move.read_group(domain_move_out_done, ['product_id', 'product_qty'], ['product_id'], orderby='id'))
res = dict()
for product in self.with_context(prefetch_fields=False):
@@ -288,7 +288,7 @@ class Product(models.Model):
domain_quant.append(('owner_id', '=', owner_id))
if package_id:
domain_quant.append(('package_id', '=', package_id))
- quants_groupby = self.env['stock.quant'].read_group(domain_quant, ['product_id', 'qty'], ['product_id'])
+ quants_groupby = self.env['stock.quant'].read_group(domain_quant, ['product_id', 'qty'], ['product_id'], orderby='id')
for quant in quants_groupby:
if OPERATORS[operator](quant['qty'], value):
product_ids.add(quant['product_id'][0])
diff --git a/addons/web/static/src/js/views/form_common.js b/addons/web/static/src/js/views/form_common.js
index 24c64aad7a4..dbbc46f3fcf 100644
--- a/addons/web/static/src/js/views/form_common.js
+++ b/addons/web/static/src/js/views/form_common.js
@@ -174,8 +174,8 @@ var CompletionFieldMixin = {
init: function() {
this.limit = 7;
this.orderer = new utils.DropMisordered();
- this.can_create = this.node.attrs.can_create || true;
- this.can_write = this.node.attrs.can_write || true;
+ this.can_create = this.node.attrs.can_create == "false" ? false : true;
+ this.can_write = this.node.attrs.can_write == "false" ? false : true;
},
/**
* Call this method to search using a string.
diff --git a/addons/web/static/src/js/views/form_view.js b/addons/web/static/src/js/views/form_view.js
index 4f141570902..98cce6e484a 100644
--- a/addons/web/static/src/js/views/form_view.js
+++ b/addons/web/static/src/js/views/form_view.js
@@ -1091,7 +1091,8 @@ var FormView = View.extend(common.FieldManagerMixin, {
|| field.field.type === 'one2many'
|| field.field.type === 'many2many'
|| field.field.type === 'binary'
- || field.password) {
+ || field.password
+ || !_.isEmpty(field.field.depends)) {
return false;
}
diff --git a/addons/web_editor/static/src/js/summernote.js b/addons/web_editor/static/src/js/summernote.js
index 71647828cc6..d28279d57ed 100644
--- a/addons/web_editor/static/src/js/summernote.js
+++ b/addons/web_editor/static/src/js/summernote.js
@@ -504,7 +504,7 @@ dom.removeBetween = function (sc, so, ec, eo, towrite) {
};
for (var i=0; i