We appreciate your feedback. It helps us to improve continuously.
-
+
diff --git a/addons/rating_project/models/project.py b/addons/rating_project/models/project.py
index 345576768ae..5c4eb6fc119 100644
--- a/addons/rating_project/models/project.py
+++ b/addons/rating_project/models/project.py
@@ -4,6 +4,7 @@
from datetime import timedelta
from odoo import api, fields, models
+from odoo.tools.safe_eval import safe_eval
class ProjectTaskType(models.Model):
@@ -104,7 +105,9 @@ class Project(models.Model):
def action_view_task_rating(self):
""" return the action to see all the rating about the tasks of the project """
action = self.env['ir.actions.act_window'].for_xml_id('rating', 'action_view_rating')
- return dict(action, domain=[('res_id', 'in', self.tasks.ids), ('res_model', '=', 'project.task')])
+ action_domain = safe_eval(action['domain']) if action['domain'] else []
+ domain = action_domain + [('res_id', 'in', self.tasks.ids), ('res_model', '=', 'project.task')]
+ return dict(action, domain=domain)
@api.multi
def action_view_all_rating(self):
diff --git a/addons/rating_project_issue/models/project_issue.py b/addons/rating_project_issue/models/project_issue.py
index 5b2b126cad2..047edd6441f 100644
--- a/addons/rating_project_issue/models/project_issue.py
+++ b/addons/rating_project_issue/models/project_issue.py
@@ -4,6 +4,7 @@
from datetime import timedelta
from odoo import api, fields, models
+from odoo.tools.safe_eval import safe_eval
class ProjectIssue(models.Model):
@@ -28,7 +29,6 @@ class ProjectIssue(models.Model):
return super(ProjectIssue, self).rating_apply(rate, token=token, feedback=feedback, subtype="rating_project_issue.mt_issue_rating")
-
class Stage(models.Model):
_inherit = ['project.task.type']
@@ -45,7 +45,7 @@ class Project(models.Model):
def _send_rating_mail(self):
super(Project, self)._send_rating_mail()
for project in self:
- project.issue_ids._send_issue_rating_mail()
+ self.env['project.issue'].search([('project_id', '=', project.id)])._send_issue_rating_mail()
@api.depends('percentage_satisfaction_task', 'percentage_satisfaction_issue')
def _compute_percentage_satisfaction_project(self):
@@ -58,7 +58,7 @@ class Project(models.Model):
activity_great = activity_task['great']
activity_sum = sum(activity_task.values())
if project.use_issues:
- activity_issue = project.issue_ids.rating_get_grades(domain)
+ activity_issue = self.env['project.issue'].search([('project_id', '=', project.id)]).rating_get_grades(domain)
activity_great += activity_issue['great']
activity_sum += sum(activity_issue.values())
project.percentage_satisfaction_project = activity_great * 100 / activity_sum if activity_sum else -1
@@ -77,7 +77,9 @@ class Project(models.Model):
""" return the action to see all the rating about the issues of the project """
action = self.env['ir.actions.act_window'].for_xml_id('rating', 'action_view_rating')
issues = self.env['project.issue'].search([('project_id', 'in', self.ids)])
- return dict(action, domain=[('res_id', 'in', issues.ids), ('res_model', '=', 'project.issue')])
+ action_domain = safe_eval(action['domain']) if action['domain'] else []
+ domain = action_domain + [('res_id', 'in', issues.ids), ('res_model', '=', 'project.issue')]
+ return dict(action, domain=domain)
@api.multi
def action_view_all_rating(self):
diff --git a/addons/stock/models/stock_picking.py b/addons/stock/models/stock_picking.py
index 7ae10fe6bfc..b3cbaad92a3 100644
--- a/addons/stock/models/stock_picking.py
+++ b/addons/stock/models/stock_picking.py
@@ -108,6 +108,15 @@ class PickingType(models.Model):
res.append((picking_type.id, name))
return res
+ @api.model
+ def name_search(self, name, args=None, operator='ilike', limit=100):
+ args = args or []
+ domain = []
+ if name:
+ domain = ['|', ('name', operator, name), ('warehouse_id.name', operator, name)]
+ picks = self.search(domain + args, limit=limit)
+ return picks.name_get()
+
@api.onchange('code')
def onchange_picking_code(self):
if self.code == 'incoming':
diff --git a/addons/stock_account/models/product.py b/addons/stock_account/models/product.py
index a81b0260253..6f0c4e7a351 100644
--- a/addons/stock_account/models/product.py
+++ b/addons/stock_account/models/product.py
@@ -40,7 +40,7 @@ class ProductTemplate(models.Model):
@api.one
@api.depends('property_valuation', 'categ_id.property_valuation')
def _compute_valuation_type(self):
- self.valuation = self.property_valuation if self.property_valuation else self.categ_id.property_valuation
+ self.valuation = self.property_valuation or self.categ_id.property_valuation
@api.one
def _set_valuation_type(self):
@@ -49,7 +49,7 @@ class ProductTemplate(models.Model):
@api.one
@api.depends('property_cost_method', 'categ_id.property_cost_method')
def _compute_cost_method(self):
- self.cost_method = self.property_cost_method if self.property_cost_method else self.categ_id.property_cost_method
+ self.cost_method = self.property_cost_method or self.categ_id.property_cost_method
@api.one
def _set_cost_method(self):
@@ -57,9 +57,8 @@ class ProductTemplate(models.Model):
@api.onchange('type')
def onchange_type_valuation(self):
- if self.type != 'product':
- self.valuation = 'manual_periodic'
- return {}
+ # TO REMOVE IN MASTER
+ pass
@api.multi
def _get_product_accounts(self):
@@ -90,9 +89,8 @@ class ProductProduct(models.Model):
@api.onchange('type')
def onchange_type_valuation(self):
- if self.type != 'product':
- self.valuation = 'manual_periodic'
- return {}
+ # TO REMOVE IN MASTER
+ pass
@api.multi
def do_change_standard_price(self, new_price, account_id):
diff --git a/addons/stock_account/views/product_views.xml b/addons/stock_account/views/product_views.xml
index 94f9bcac870..4ba2938c0ea 100644
--- a/addons/stock_account/views/product_views.xml
+++ b/addons/stock_account/views/product_views.xml
@@ -33,8 +33,8 @@
-
-
+
+
diff --git a/addons/web/static/src/js/views/list_view.js b/addons/web/static/src/js/views/list_view.js
index cdf2ff18c63..e92437d1551 100644
--- a/addons/web/static/src/js/views/list_view.js
+++ b/addons/web/static/src/js/views/list_view.js
@@ -1098,7 +1098,7 @@ ListView.List = Class.extend({
}
}
return column.format(record.toForm().data, {
- model: this.model,
+ model: this.dataset.model,
id: record.get('id')
});
},
diff --git a/addons/web_editor/static/src/js/summernote.js b/addons/web_editor/static/src/js/summernote.js
index 101c3463e6e..28bfe83a345 100644
--- a/addons/web_editor/static/src/js/summernote.js
+++ b/addons/web_editor/static/src/js/summernote.js
@@ -2302,13 +2302,16 @@ eventHandler.modules.popover.update = function ($popover, oStyle, isAirMode) {
}
};
-options.onPaste = function (e) {
- e.preventDefault(); // FIXME this does not work with our custom out-dated summernote.
- document.execCommand("undo"); // FIXME ... so use this hack until we decide to do something about it.
-
- var pastedText = ((e.originalEvent || e).clipboardData || window.clipboardData).getData('Text');
- var formattedText = pastedText.replace(/([^.!?:;])\r?\n/g, "$1").trim(); // Remove linebreaks which are not at the end of a sentence
- document.execCommand("insertText", false, formattedText);
+// override summernote clipboard functionality
+eventHandler.modules.clipboard.attach = function(layoutInfo) {
+ var $editable = layoutInfo.editable();
+ $editable.on('paste', function(e) {
+ e.preventDefault();
+ $editable.data('NoteHistory').recordUndo($editable);
+ var pastedText = ((e.originalEvent || e).clipboardData || window.clipboardData).getData('Text');
+ var formattedText = pastedText.replace(/([^.!?:;])\r?\n/g, "$1").trim(); // Remove linebreaks which are not at the end of a sentence
+ document.execCommand("insertText", false, formattedText);
+ });
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/addons/website/models/ir_http.py b/addons/website/models/ir_http.py
index b1a0fff4e10..3edf0313e3f 100644
--- a/addons/website/models/ir_http.py
+++ b/addons/website/models/ir_http.py
@@ -166,14 +166,13 @@ class Http(models.AbstractModel):
langs = [lg[0] for lg in request.website.get_languages()]
path = request.httprequest.path.split('/')
if first_pass:
+ is_a_bot = cls.is_a_bot()
nearest_lang = not func and cls.get_nearest_lang(path[1])
url_lang = nearest_lang and path[1]
preferred_lang = ((cook_lang if cook_lang in langs else False)
- or cls.get_nearest_lang(request.lang)
+ or (not is_a_bot and cls.get_nearest_lang(request.lang))
or request.website.default_lang_code)
- is_a_bot = cls.is_a_bot()
-
request.lang = context['lang'] = nearest_lang or preferred_lang
# if lang in url but not the displayed or default language --> change or remove
# or no lang in url, and lang to dispay not the default language --> add lang
diff --git a/addons/website_blog/controllers/main.py b/addons/website_blog/controllers/main.py
index e21696d63b2..a466dcf3701 100644
--- a/addons/website_blog/controllers/main.py
+++ b/addons/website_blog/controllers/main.py
@@ -4,6 +4,9 @@
import json
import werkzeug
import itertools
+import pytz
+import babel.dates
+from collections import OrderedDict
from odoo import http, fields, _
from odoo.addons.website.controllers.main import QueryURL
@@ -29,13 +32,20 @@ class WebsiteBlog(http.Controller):
(r, label) = group['post_date']
start, end = r.split('/')
group['post_date'] = label
- group['date_begin'] = fields.Date.to_string(self._to_date(start))
- group['date_end'] = fields.Date.to_string(self._to_date(end))
- group['month'] = self._to_date(start).strftime("%B")
- group['year'] = self._to_date(start).strftime("%Y")
- return {year: [m for m in months] for year, months in itertools.groupby(groups, lambda g: g['year'])}
+ group['date_begin'] = start
+ group['date_end'] = end
+
+ locale = request.context.get('lang', 'en_US')
+ start = pytz.UTC.localize(fields.Datetime.from_string(start))
+ tzinfo = pytz.timezone(request.context.get('tz', 'utc') or 'utc')
+
+ group['month'] = babel.dates.format_datetime(start, format='MMMM', tzinfo=tzinfo, locale=locale)
+ group['year'] = babel.dates.format_datetime(start, format='YYYY', tzinfo=tzinfo, locale=locale)
+
+ return OrderedDict((year, [m for m in months]) for year, months in itertools.groupby(groups, lambda g: g['year']))
def _to_date(self, dt):
+ # TODO remove me in master/saas-14
return fields.Date.from_string(dt)
@http.route([
diff --git a/addons/website_event/views/website_event_templates.xml b/addons/website_event/views/website_event_templates.xml
index b205a3a58b0..918c59e3d1e 100644
--- a/addons/website_event/views/website_event_templates.xml
+++ b/addons/website_event/views/website_event_templates.xml
@@ -241,7 +241,7 @@
@@ -342,7 +342,7 @@
@@ -521,7 +521,7 @@
to
diff --git a/addons/website_quote/controllers/main.py b/addons/website_quote/controllers/main.py
index 0fcb9485d76..01d36059fad 100644
--- a/addons/website_quote/controllers/main.py
+++ b/addons/website_quote/controllers/main.py
@@ -30,6 +30,7 @@ class sale_quote(http.Controller):
if not Order:
return request.render('website.404')
+ request.session['sale_order_id'] = Order.id
days = 0
if Order.validity_date:
diff --git a/addons/website_quote/views/website_quote_templates.xml b/addons/website_quote/views/website_quote_templates.xml
index 4865662ff70..d9cff518c86 100644
--- a/addons/website_quote/views/website_quote_templates.xml
+++ b/addons/website_quote/views/website_quote_templates.xml
@@ -701,7 +701,12 @@
|
-
+
+
+
+
+
+
|
|
diff --git a/doc/cla/individual/Nowheresly.md b/doc/cla/individual/Nowheresly.md
new file mode 100644
index 00000000000..51ea23e893f
--- /dev/null
+++ b/doc/cla/individual/Nowheresly.md
@@ -0,0 +1,11 @@
+Luxembourg, 2016-10-26
+
+I hereby agree to the terms of the Odoo Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Sylvère Richard sylvere.richard@gmail.com https://github.com/Nowheresly
diff --git a/odoo/fields.py b/odoo/fields.py
index 36086c0dfe2..e5cd453ed1d 100644
--- a/odoo/fields.py
+++ b/odoo/fields.py
@@ -301,7 +301,7 @@ class Field(object):
'args': EMPTY_DICT, # the parameters given to __init__()
'_attrs': EMPTY_DICT, # the field's non-slot attributes
'_module': None, # the field's module name
- 'setup_full_done': False, # whether the field has been fully setup
+ '_setup_done': None, # the field's setup state: None, 'base' or 'full'
'automatic': False, # whether the field is automatically created ("magic" field)
'inherited': False, # whether the field is inherited (_inherits)
@@ -345,7 +345,7 @@ class Field(object):
kwargs['string'] = string
args = {key: val for key, val in kwargs.iteritems() if val is not Default}
self.args = args or EMPTY_DICT
- self.setup_full_done = False
+ self._setup_done = None
def new(self, **kwargs):
""" Return a field of the same type as ``self``, with its own parameters. """
@@ -397,14 +397,15 @@ class Field(object):
def setup_base(self, model, name):
""" Base setup: things that do not depend on other models/fields. """
- if self.setup_full_done and not self.related:
+ if self._setup_done and not self.related:
# optimization for regular fields: keep the base setup
- self.setup_full_done = False
+ self._setup_done = 'base'
else:
# do the base setup from scratch
self._setup_attrs(model, name)
if not self.related:
self._setup_regular_base(model)
+ self._setup_done = 'base'
#
# Setup field parameter attributes
@@ -483,12 +484,12 @@ class Field(object):
def setup_full(self, model):
""" Full setup: everything else, except recomputation triggers. """
- if not self.setup_full_done:
+ if self._setup_done != 'full':
if not self.related:
self._setup_regular_full(model)
else:
self._setup_related_full(model)
- self.setup_full_done = True
+ self._setup_done = 'full'
#
# Setup of non-related fields
diff --git a/odoo/tests/common.py b/odoo/tests/common.py
index 0d0d352f670..883904cd8c1 100644
--- a/odoo/tests/common.py
+++ b/odoo/tests/common.py
@@ -86,6 +86,8 @@ class BaseCase(unittest.TestCase):
initialized by subclasses.
"""
+ longMessage = True # more verbose error message by default: https://www.odoo.com/r/Vmh
+
def cursor(self):
return self.registry.cursor()
diff --git a/odoo/tools/config.py b/odoo/tools/config.py
index b05fd1a018b..2473fe53304 100644
--- a/odoo/tools/config.py
+++ b/odoo/tools/config.py
@@ -111,7 +111,7 @@ class configmanager(object):
group.add_option("--addons-path", dest="addons_path",
help="specify additional addons paths (separated by commas).",
action="callback", callback=self._check_addons_path, nargs=1, type="string")
- group.add_option("--load", dest="server_wide_modules", help="Comma-separated list of server-wide modules. Default is 'web,web_kanban'")
+ group.add_option("--load", dest="server_wide_modules", help="Comma-separated list of server-wide modules.", my_default='web,web_kanban')
group.add_option("-D", "--data-dir", dest="data_dir", my_default=_get_default_datadir(),
help="Directory where to store Odoo data")
@@ -372,6 +372,9 @@ class configmanager(object):
# the same for the pidfile
if self.options['pidfile'] in ('None', 'False'):
self.options['pidfile'] = False
+ # and the server_wide_modules
+ if self.options['server_wide_modules'] in ('', 'None', 'False'):
+ self.options['server_wide_modules'] = 'web,web_kanban'
# if defined dont take the configfile value even if the defined value is None
keys = ['xmlrpc_interface', 'xmlrpc_port', 'longpolling_port',
@@ -460,20 +463,13 @@ class configmanager(object):
if len(self.options['language']) > 5:
raise Exception('ERROR: The Lang name must take max 5 chars, Eg: -lfr_BE')
- # server_wide_modules defaults to web,web_kanban if empty or unset
- server_wide_modules = self.options['server_wide_modules'] = (
- self.options['server_wide_modules']
- if self.options['server_wide_modules']
- else 'web,web_kanban'
- )
-
if opt.save:
self.save()
odoo.conf.addons_paths = self.options['addons_path'].split(',')
odoo.conf.server_wide_modules = [
- m.strip() for m in server_wide_modules.split(',')
+ m.strip() for m in self.options['server_wide_modules'].split(',') if m.strip()
]
def _is_addons_path(self, path):
| | |