Click to create a recipient.
@@ -691,6 +691,7 @@
+
diff --git a/addons/mrp/models/stock_move.py b/addons/mrp/models/stock_move.py
index ad1a50ad738..1fee94e7f5f 100644
--- a/addons/mrp/models/stock_move.py
+++ b/addons/mrp/models/stock_move.py
@@ -386,3 +386,12 @@ class StockMove(models.Model):
'split_from': self.id, # Needed in order to keep sale connection, but will be removed by unlink
})
return self.env['stock.move']
+
+class PushedFlow(models.Model):
+ _inherit = "stock.location.path"
+
+ def _prepare_move_copy_values(self, move_to_copy, new_date):
+ new_move_vals = super(PushedFlow, self)._prepare_move_copy_values(move_to_copy, new_date)
+ new_move_vals['production_id'] = False
+
+ return new_move_vals
diff --git a/addons/payment_paypal/controllers/main.py b/addons/payment_paypal/controllers/main.py
index 2fefb1417ef..00359c4d038 100644
--- a/addons/payment_paypal/controllers/main.py
+++ b/addons/payment_paypal/controllers/main.py
@@ -23,7 +23,7 @@ class PaypalController(http.Controller):
""" Extract the return URL from the data coming from paypal. """
return_url = post.pop('return_url', '')
if not return_url:
- custom = json.loads(post.pop('custom', False) or post.pop('cm', False) or '{}')
+ custom = json.loads(urllib.unquote_plus(post.pop('custom', False) or post.pop('cm', False) or '{}'))
return_url = custom.get('return_url', '/')
return return_url
diff --git a/addons/product/models/product_attribute.py b/addons/product/models/product_attribute.py
index 9c9a8c09388..bdedd9d7f9d 100644
--- a/addons/product/models/product_attribute.py
+++ b/addons/product/models/product_attribute.py
@@ -76,7 +76,7 @@ class ProductAttributevalue(models.Model):
@api.multi
def _variant_name(self, variable_attributes):
- return ", ".join([v.name for v in self if v.attribute_id in variable_attributes])
+ return ", ".join([v.name for v in self.sorted(key=lambda r: r.name) if v.attribute_id in variable_attributes])
class ProductAttributePrice(models.Model):
diff --git a/addons/product/models/product_pricelist.py b/addons/product/models/product_pricelist.py
index 45cc87d17ae..c4dc828b540 100644
--- a/addons/product/models/product_pricelist.py
+++ b/addons/product/models/product_pricelist.py
@@ -44,7 +44,7 @@ class Pricelist(models.Model):
if name and operator == '=' and not args:
# search on the name of the pricelist and its currency, opposite of name_get(),
# Used by the magic context filter in the product search view.
- query_args = {'name': name, 'limit': limit, 'lang': self._context.get('lang', 'en_US')}
+ query_args = {'name': name, 'limit': limit, 'lang': self._context.get('lang') or 'en_US'}
query = """SELECT p.id
FROM ((
SELECT pr.id, pr.name
diff --git a/addons/sale/models/sale.py b/addons/sale/models/sale.py
index a30cb13aa78..12d93931bc8 100644
--- a/addons/sale/models/sale.py
+++ b/addons/sale/models/sale.py
@@ -347,7 +347,7 @@ class SaleOrder(models.Model):
vals = {}
if order.name not in invoices[group_key].origin.split(', '):
vals['origin'] = invoices[group_key].origin + ', ' + order.name
- if order.client_order_ref and order.client_order_ref not in invoices[group_key].name.split(', '):
+ if order.client_order_ref and order.client_order_ref not in invoices[group_key].name.split(', ') and order.client_order_ref != invoices[group_key].name:
vals['name'] = invoices[group_key].name + ', ' + order.client_order_ref
invoices[group_key].write(vals)
if line.qty_to_invoice > 0:
@@ -822,7 +822,6 @@ class SaleOrderLine(models.Model):
'uom_id': self.product_uom.id,
'product_id': self.product_id.id or False,
'layout_category_id': self.layout_category_id and self.layout_category_id.id or False,
- 'product_id': self.product_id.id or False,
'invoice_line_tax_ids': [(6, 0, self.tax_id.ids)],
'account_analytic_id': self.order_id.project_id.id,
'analytic_tag_ids': [(6, 0, self.analytic_tag_ids.ids)],
diff --git a/addons/stock/models/stock_location.py b/addons/stock/models/stock_location.py
index 17f8816b6c6..540bd6f1a06 100644
--- a/addons/stock/models/stock_location.py
+++ b/addons/stock/models/stock_location.py
@@ -213,9 +213,15 @@ class PushedFlow(models.Model):
# TDE FIXME: should probably be done in the move model IMO
move._push_apply()
else:
- new_move = move.copy({
- 'origin': move.origin or move.picking_id.name or "/",
- 'location_id': move.location_dest_id.id,
+ new_move_vals = self._prepare_move_copy_values(move, new_date)
+ new_move = move.copy(new_move_vals)
+ move.write({'move_dest_id': new_move.id})
+ new_move.action_confirm()
+
+ def _prepare_move_copy_values(self, move_to_copy, new_date):
+ new_move_vals = {
+ 'origin': move_to_copy.origin or move_to_copy.picking_id.name or "/",
+ 'location_id': move_to_copy.location_dest_id.id,
'location_dest_id': self.location_dest_id.id,
'date': new_date,
'date_expected': new_date,
@@ -226,6 +232,6 @@ class PushedFlow(models.Model):
'push_rule_id': self.id,
'warehouse_id': self.warehouse_id.id,
'procurement_id': False,
- })
- move.write({'move_dest_id': new_move.id})
- new_move.action_confirm()
+ }
+
+ return new_move_vals
diff --git a/addons/stock/models/stock_quant.py b/addons/stock/models/stock_quant.py
index 9c95a6682ac..1d144695f52 100644
--- a/addons/stock/models/stock_quant.py
+++ b/addons/stock/models/stock_quant.py
@@ -520,7 +520,7 @@ class Quant(models.Model):
if any(quant not in self for quant in package.get_content()):
all_in = False
if all_in:
- destinations = [product_to_location[product] for product in package.get_content().mapped('product_id')]
+ destinations = set([product_to_location[product] for product in package.get_content().mapped('product_id')])
if len(destinations) > 1:
all_in = False
if all_in:
diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py
index 39c0c34983c..f7b799b3bfd 100644
--- a/addons/web/controllers/main.py
+++ b/addons/web/controllers/main.py
@@ -54,6 +54,8 @@ env.filters["json"] = json.dumps
# 1 week cache for asset bundles as advised by Google Page Speed
BUNDLE_MAXAGE = 60 * 60 * 24 * 7
+DBNAME_PATTERN = '^[a-zA-Z0-9][a-zA-Z0-9_.-]+$'
+
#----------------------------------------------------------
# Odoo Web helpers
#----------------------------------------------------------
@@ -630,6 +632,7 @@ class Database(http.Controller):
d['list_db'] = odoo.tools.config['list_db']
d['langs'] = odoo.service.db.exp_list_lang()
d['countries'] = odoo.service.db.exp_list_countries()
+ d['pattern'] = DBNAME_PATTERN
# databases list
d['databases'] = []
try:
@@ -654,8 +657,8 @@ class Database(http.Controller):
@http.route('/web/database/create', type='http', auth="none", methods=['POST'], csrf=False)
def create(self, master_pwd, name, lang, password, **post):
try:
- if not re.match('^[a-zA-Z][a-zA-Z0-9_]+$', name):
- raise Exception(_('Invalid database name. Only alphanumerical characters and underscore are allowed.'))
+ if not re.match(DBNAME_PATTERN, name):
+ raise Exception(_('Invalid database name. Only alphanumerical characters, underscore, hyphen and dot are allowed.'))
# country code could be = "False" which is actually True in python
country_code = post.get('country_code') or False
dispatch_rpc('db', 'create_database', [master_pwd, name, bool(post.get('demo')), lang, password, post['login'], country_code])
@@ -668,8 +671,8 @@ class Database(http.Controller):
@http.route('/web/database/duplicate', type='http', auth="none", methods=['POST'], csrf=False)
def duplicate(self, master_pwd, name, new_name):
try:
- if not re.match('^[a-zA-Z][a-zA-Z0-9_]+$', new_name):
- raise Exception(_('Invalid database name. Only alphanumerical characters and underscore are allowed.'))
+ if not re.match(DBNAME_PATTERN, new_name):
+ raise Exception(_('Invalid database name. Only alphanumerical characters, underscore, hyphen and dot are allowed.'))
dispatch_rpc('db', 'duplicate_database', [master_pwd, name, new_name])
return http.local_redirect('/web/database/manager')
except Exception, e:
diff --git a/addons/web/static/lib/qweb/qweb2.js b/addons/web/static/lib/qweb/qweb2.js
index 1e854a6960c..378c5eb6023 100644
--- a/addons/web/static/lib/qweb/qweb2.js
+++ b/addons/web/static/lib/qweb/qweb2.js
@@ -129,12 +129,15 @@ var QWeb2 = {
}
return r.join('');
} else {
+ // avoid XMLSerializer with text node for IE
+ if (node.nodeType == 3) {
+ return node.data;
+ }
if (typeof XMLSerializer !== 'undefined') {
return (new XMLSerializer()).serializeToString(node);
} else {
switch(node.nodeType) {
case 1: return node.outerHTML;
- case 3: return node.data;
case 4: return '';
case 8: return '';
}
diff --git a/addons/web/views/database_manager.html b/addons/web/views/database_manager.html
index 7f91bc73907..7f0d2fc04ff 100644
--- a/addons/web/views/database_manager.html
+++ b/addons/web/views/database_manager.html
@@ -60,7 +60,7 @@
@@ -210,7 +210,7 @@
-
+
@@ -283,7 +283,7 @@
-
+