diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py index baef7d7aa2a..68e77e0a96f 100644 --- a/addons/account/models/account_move.py +++ b/addons/account/models/account_move.py @@ -916,8 +916,8 @@ class AccountMoveLine(models.Model): # Writeoff line in the account of self first_line_dict = vals.copy() first_line_dict['account_id'] = self[0].account_id.id - if 'analytic_account_id' in vals: - del vals['analytic_account_id'] + if 'analytic_account_id' in first_line_dict: + del first_line_dict['analytic_account_id'] # Writeoff line in specified writeoff account second_line_dict = vals.copy() diff --git a/addons/account/views/partner_view.xml b/addons/account/views/partner_view.xml index c7bec407b85..23a07d1caf1 100644 --- a/addons/account/views/partner_view.xml +++ b/addons/account/views/partner_view.xml @@ -39,11 +39,11 @@ - +
- + diff --git a/addons/base_action_rule/models/base_action_rule.py b/addons/base_action_rule/models/base_action_rule.py index 50cbfced8fb..15368923816 100644 --- a/addons/base_action_rule/models/base_action_rule.py +++ b/addons/base_action_rule/models/base_action_rule.py @@ -124,7 +124,7 @@ class BaseActionRule(models.Model): def _update_registry(self): """ Update the registry after a modification on action rules. """ - if self.env.registry.ready: + if self.env.registry.ready and not self.env.context.get('import_file'): # for the sake of simplicity, simply force the registry to reload self._cr.commit() self.env.reset() diff --git a/addons/base_import/models.py b/addons/base_import/models.py index 4c4a9fd6c15..09879c7a15d 100644 --- a/addons/base_import/models.py +++ b/addons/base_import/models.py @@ -634,7 +634,7 @@ class ir_import(orm.TransientModel): _logger.info('importing %d rows...', len(data)) import_result = self.pool[record.res_model].load( - cr, uid, import_fields, data, context=context) + cr, uid, import_fields, data, context=dict(context, import_file=True)) _logger.info('done') # If transaction aborted, RELEASE SAVEPOINT is going to raise diff --git a/addons/crm/crm_lead_view.xml b/addons/crm/crm_lead_view.xml index 0af44f14bc3..4e45a1a7bc0 100644 --- a/addons/crm/crm_lead_view.xml +++ b/addons/crm/crm_lead_view.xml @@ -530,7 +530,7 @@ - + diff --git a/addons/mail/models/mail_template.py b/addons/mail/models/mail_template.py index 99897cf13de..83db6d943fc 100644 --- a/addons/mail/models/mail_template.py +++ b/addons/mail/models/mail_template.py @@ -50,7 +50,7 @@ def format_tz(pool, cr, uid, dt, tz=False, format=False, context=None): format_time = lang_params.get("time_format", '%I-%M %p') fdate = ts.strftime(format_date).decode('utf-8') - ftime = ts.strftime(format_time) + ftime = ts.strftime(format_time).decode('utf-8') return "%s %s%s" % (fdate, ftime, (' (%s)' % tz) if tz else '') try: diff --git a/addons/point_of_sale/security/point_of_sale_security.xml b/addons/point_of_sale/security/point_of_sale_security.xml index d5928cf5332..918d926d877 100644 --- a/addons/point_of_sale/security/point_of_sale_security.xml +++ b/addons/point_of_sale/security/point_of_sale_security.xml @@ -39,12 +39,6 @@ [(1, '=', 1)] - - Point Of Sale Cashbox Line POS User - - - [('bank_statement_id.pos_session_id', '!=', False)] - Point Of Sale Cashbox Line Accountant diff --git a/addons/web/static/src/js/views/list_view.js b/addons/web/static/src/js/views/list_view.js index c26eccae709..128fead3894 100644 --- a/addons/web/static/src/js/views/list_view.js +++ b/addons/web/static/src/js/views/list_view.js @@ -1705,7 +1705,6 @@ var Column = Class.extend({ id: id, tag: tag }); - this.modifiers = attrs.modifiers ? JSON.parse(attrs.modifiers) : {}; delete attrs.modifiers; _.extend(this, attrs); @@ -1732,10 +1731,14 @@ var Column = Class.extend({ if (this.type !== 'integer' && this.type !== 'float' && this.type !== 'monetary') { return {}; } - var aggregation_func = this['group_operator'] || 'sum'; - if (!(aggregation_func in this)) { + + var aggregation_func = (this.sum && 'sum') || (this.avg && 'avg') || + (this.max && 'max') || (this.min && 'min') || this.group_operator; + + if (!aggregation_func) { return {}; } + var C = function (fn, label) { this['function'] = fn; this.label = label; diff --git a/addons/website/static/src/js/website.snippets.animation.js b/addons/website/static/src/js/website.snippets.animation.js index a278ed1196e..c7b8e60ccad 100644 --- a/addons/website/static/src/js/website.snippets.animation.js +++ b/addons/website/static/src/js/website.snippets.animation.js @@ -150,6 +150,20 @@ animation.registry.ul = animation.Class.extend({ }, }); +/** + * This is a fix for apple device (<= IPhone 4, IPad 2) + * Standard bootstrap requires data-toggle='collapse' element to be tags. Unfortunatly one snippet uses a + *
tag instead. The fix forces an empty click handler on these div, which allows standard bootstrap to work. + * + * This should be removed in a future odoo snippets refactoring. + */ +animation.registry._fix_apple_collapse = animation.Class.extend({ + selector: ".s_faq_collapse [data-toggle='collapse']", + start: function () { + this.$target.off("click._fix_apple_collapse").on("click._fix_apple_collapse", function () {}); + }, +}); + /* ------------------------------------------------------------------------- Gallery Animation diff --git a/addons/website_livechat/__openerp__.py b/addons/website_livechat/__openerp__.py index 6161d3f8673..9caf3260d36 100644 --- a/addons/website_livechat/__openerp__.py +++ b/addons/website_livechat/__openerp__.py @@ -12,6 +12,7 @@ It also will include the feedback tool for the livechat, and web pages to displa """, 'depends': ['website', 'im_livechat'], 'installable': True, + 'auto_install': True, 'data': [ 'views/website_livechat.xml', 'views/res_config.xml', diff --git a/openerp/addons/base/res/res_partner.py b/openerp/addons/base/res/res_partner.py index 5839706c77f..3b12ac011f8 100644 --- a/openerp/addons/base/res/res_partner.py +++ b/openerp/addons/base/res/res_partner.py @@ -204,7 +204,7 @@ class Partner(models.Model, FormatAddress): # technical field used for managing commercial fields commercial_partner_id = fields.Many2one('res.partner', compute='_compute_commercial_partner', - string='Commercial Entity', store=True) + string='Commercial Entity', store=True, index=True) # image: all image fields are base64 encoded and PIL-supported image = fields.Binary("Image", attachment=True, diff --git a/openerp/addons/test_new_api/models.py b/openerp/addons/test_new_api/models.py index af664a5c9cb..620202c0576 100644 --- a/openerp/addons/test_new_api/models.py +++ b/openerp/addons/test_new_api/models.py @@ -139,10 +139,17 @@ class Discussion(models.Model): message_concat = fields.Text(string='Message concatenate') important_messages = fields.One2many('test_new_api.message', 'discussion', domain=[('important', '=', True)]) + very_important_messages = fields.One2many( + 'test_new_api.message', 'discussion', + domain=lambda self: self._domain_very_important()) emails = fields.One2many('test_new_api.emailmessage', 'discussion') important_emails = fields.One2many('test_new_api.emailmessage', 'discussion', domain=[('important', '=', True)]) + def _domain_very_important(self): + """Ensure computed O2M domains work as expected.""" + return [("important", "=", True)] + @api.onchange('moderator') def _onchange_moderator(self): self.participants |= self.moderator diff --git a/openerp/addons/test_new_api/tests/test_new_fields.py b/openerp/addons/test_new_api/tests/test_new_fields.py index 7d843fa1f70..7ca55c4eabd 100644 --- a/openerp/addons/test_new_api/tests/test_new_fields.py +++ b/openerp/addons/test_new_api/tests/test_new_fields.py @@ -500,6 +500,12 @@ class TestNewFields(common.TransactionCase): message.important = True self.assertIn(message, discussion.important_messages) + # writing on very_important_messages should call its domain method + self.assertIn(message, discussion.very_important_messages) + discussion.write({'very_important_messages': [(5,)]}) + self.assertFalse(discussion.very_important_messages) + self.assertFalse(message.exists()) + class TestMagicFields(common.TransactionCase): diff --git a/openerp/fields.py b/openerp/fields.py index 9ceb7a43b14..0a3e65251f4 100644 --- a/openerp/fields.py +++ b/openerp/fields.py @@ -1067,6 +1067,7 @@ class Integer(Field): } _related_group_operator = property(attrgetter('group_operator')) + _description_group_operator = property(attrgetter('group_operator')) _column_group_operator = property(attrgetter('group_operator')) def convert_to_cache(self, value, record, validate=True): @@ -1119,6 +1120,7 @@ class Float(Field): _related_group_operator = property(attrgetter('group_operator')) _description_digits = property(attrgetter('digits')) + _description_group_operator = property(attrgetter('group_operator')) _column_digits = property(lambda self: not callable(self._digits) and self._digits) _column_digits_compute = property(lambda self: callable(self._digits) and self._digits) @@ -1157,6 +1159,7 @@ class Monetary(Field): _related_group_operator = property(attrgetter('group_operator')) _description_currency_field = property(attrgetter('currency_field')) + _description_group_operator = property(attrgetter('group_operator')) _column_currency_field = property(attrgetter('currency_field')) _column_group_operator = property(attrgetter('group_operator')) @@ -1230,7 +1233,7 @@ class _String(Field): return self.translate(callback, value) else: return value - + class Char(_String): """ Basic string field, can be length-limited, usually displayed as a diff --git a/openerp/osv/fields.py b/openerp/osv/fields.py index c4a2a0706e5..fda32b45332 100644 --- a/openerp/osv/fields.py +++ b/openerp/osv/fields.py @@ -827,6 +827,7 @@ class one2many(_column): context.update(self._context) if not values: return + original_obj = obj obj = obj.pool[self._obj] rec = obj.browse(cr, user, [], context=context) with rec.env.norecompute(): @@ -858,7 +859,8 @@ class one2many(_column): inverse_field = obj._fields.get(self._fields_id) assert inverse_field, 'Trying to unlink the content of a o2m but the pointed model does not have a m2o' # if the o2m has a static domain we must respect it when unlinking - domain = self._domain(obj) if callable(self._domain) else self._domain + domain = (self._domain(original_obj) + if callable(self._domain) else self._domain) extra_domain = domain or [] ids_to_unlink = obj.search(cr, user, [(self._fields_id,'=',id)] + extra_domain, context=context) # If the model has cascade deletion, we delete the rows because it is the intended behavior, diff --git a/openerp/tools/config.py b/openerp/tools/config.py index 1be530a1c58..01c26b2ec4e 100644 --- a/openerp/tools/config.py +++ b/openerp/tools/config.py @@ -432,7 +432,7 @@ class configmanager(object): for x in self.options['addons_path'].split(',')) self.options['init'] = opt.init and dict.fromkeys(opt.init.split(','), 1) or {} - self.options['demo'] = (self.options['init'] + self.options['demo'] = (dict(self.options['init']) if not self.options['without_demo'] else {}) self.options['update'] = opt.update and dict.fromkeys(opt.update.split(','), 1) or {} self.options['translate_modules'] = opt.translate_modules and map(lambda m: m.strip(), opt.translate_modules.split(',')) or ['all']