From 3ff4cdea95c525053314c750e4c1203707dada9d Mon Sep 17 00:00:00 2001 From: Goffin Simon Date: Thu, 19 Feb 2015 08:50:03 +0100 Subject: [PATCH 1/9] [FIX] pos: Bad float comparison to check amount_return in _process_order. Float comparison should always be done using float_compare, or float_is_zero when compared to 0.0. opw: 627248 Closes #4118 --- addons/point_of_sale/point_of_sale.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addons/point_of_sale/point_of_sale.py b/addons/point_of_sale/point_of_sale.py index b9e10ca5dad..0d4f0275401 100644 --- a/addons/point_of_sale/point_of_sale.py +++ b/addons/point_of_sale/point_of_sale.py @@ -24,6 +24,7 @@ import time from openerp import tools from openerp.osv import fields, osv +from openerp.tools import float_is_zero from openerp.tools.translate import _ import openerp.addons.decimal_precision as dp @@ -585,7 +586,7 @@ class pos_order(osv.osv): session.write({'sequence_number': order['sequence_number'] + 1}) session.refresh() - if order['amount_return']: + if not float_is_zero(order['amount_return'], self.pool.get('decimal.precision').precision_get(cr, uid, 'Account')): cash_journal = session.cash_journal_id if not cash_journal: cash_journal_ids = filter(lambda st: st.journal_id.type=='cash', session.statement_ids) From 4bf5ce94d20d4ddec180cd7a9ef15511c2d9784f Mon Sep 17 00:00:00 2001 From: Denis Michiels Date: Mon, 23 Feb 2015 13:38:44 +0100 Subject: [PATCH 2/9] [FIX] account_invoice : origin field for refund invoice When creating a Refund invoice, the field "origin" is fill with the number of the invoice to refund fix #5233 opw 627828 --- addons/account/account_invoice.py | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/account/account_invoice.py b/addons/account/account_invoice.py index b3e5977d1d9..2654f55150c 100644 --- a/addons/account/account_invoice.py +++ b/addons/account/account_invoice.py @@ -1098,6 +1098,7 @@ class account_invoice(models.Model): values['date_invoice'] = date or fields.Date.context_today(invoice) values['state'] = 'draft' values['number'] = False + values['origin'] = invoice.number if period_id: values['period_id'] = period_id From d13ca06c8eeaddf5c3050afaa829d50225b7d249 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Mon, 23 Feb 2015 14:25:07 +0100 Subject: [PATCH 3/9] [FIX] calendar: message_(un)subscribe expects integers In calendar, using recurrent events leads to the use of virtual ids, which are strings. It wasn't possible to change the message subscriptions for recurring events, neither for the user himself, neither for the other followers opw-627895 --- addons/calendar/calendar.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/addons/calendar/calendar.py b/addons/calendar/calendar.py index 9250e1a2a1c..28edd84426b 100644 --- a/addons/calendar/calendar.py +++ b/addons/calendar/calendar.py @@ -1416,6 +1416,12 @@ class calendar_event(osv.Model): del context['default_date'] return super(calendar_event, self).message_post(cr, uid, thread_id, body=body, subject=subject, type=type, subtype=subtype, parent_id=parent_id, attachments=attachments, context=context, **kwargs) + def message_subscribe(self, cr, uid, ids, partner_ids, subtype_ids=None, context=None): + return super(calendar_event, self).message_subscribe(cr, uid, get_real_ids(ids), partner_ids, subtype_ids=subtype_ids, context=context) + + def message_unsubscribe(self, cr, uid, ids, partner_ids, context=None): + return super(calendar_event, self).message_unsubscribe(cr, uid, get_real_ids(ids), partner_ids, context=context) + def do_sendmail(self, cr, uid, ids, context=None): for event in self.browse(cr, uid, ids, context): current_user = self.pool['res.users'].browse(cr, uid, uid, context=context) @@ -1747,7 +1753,6 @@ class calendar_event(osv.Model): return res - class mail_message(osv.Model): _inherit = "mail.message" From 25429656c7d9e229e55158f9cf8e15e2f84e4caf Mon Sep 17 00:00:00 2001 From: Arthur Maniet Date: Mon, 16 Feb 2015 19:23:36 +0100 Subject: [PATCH 4/9] [FIX] account: rounding error when the balanced operation done in bank statement reconciliation is converted to the company currency. --- addons/account/account_bank_statement.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/addons/account/account_bank_statement.py b/addons/account/account_bank_statement.py index ff81ba64421..b39b999e82c 100644 --- a/addons/account/account_bank_statement.py +++ b/addons/account/account_bank_statement.py @@ -161,7 +161,7 @@ class account_bank_statement(osv.osv): } _defaults = { - 'name': '/', + 'name': '/', 'date': fields.date.context_today, 'state': 'draft', 'journal_id': _default_journal_id, @@ -242,7 +242,7 @@ class account_bank_statement(osv.osv): def _prepare_bank_move_line(self, cr, uid, st_line, move_id, amount, company_currency_id, context=None): """Compute the args to build the dict of values to create the counter part move line from a - statement line by calling the _prepare_move_line_vals. + statement line by calling the _prepare_move_line_vals. :param browse_record st_line: account.bank.statement.line record to create the move from. :param int/long move_id: ID of the account.move to link the move line @@ -388,7 +388,7 @@ class account_bank_statement(osv.osv): for item in self.browse(cr, uid, ids, context=context): if item.state != 'draft': raise osv.except_osv( - _('Invalid Action!'), + _('Invalid Action!'), _('In order to delete a bank statement, you must first cancel it to delete related journal items.') ) # Explicitly unlink bank statement lines @@ -436,7 +436,7 @@ class account_bank_statement_line(osv.osv): for item in self.browse(cr, uid, ids, context=context): if item.journal_entry_id: raise osv.except_osv( - _('Invalid Action!'), + _('Invalid Action!'), _('In order to delete a bank statement line, you must first cancel it to delete related journal items.') ) return super(account_bank_statement_line, self).unlink(cr, uid, ids, context=context) @@ -646,7 +646,7 @@ class account_bank_statement_line(osv.osv): """ mv_line_pool = self.pool.get('account.move.line') domain = self._domain_move_lines_for_reconciliation(cr, uid, st_line, excluded_ids=excluded_ids, str=str, additional_domain=additional_domain, context=context) - + # Get move lines ; in case of a partial reconciliation, only keep one line (the first whose amount is greater than # the residual amount because it is presumably the invoice, which is the relevant item in this situation) filtered_lines = [] @@ -811,6 +811,15 @@ class account_bank_statement_line(osv.osv): prorata_factor = (mv_line_dict['debit'] - mv_line_dict['credit']) / st_line.amount_currency mv_line_dict['amount_currency'] = prorata_factor * st_line.amount to_create.append(mv_line_dict) + # If the reconciliation is performed in another currency than the company currency, the amounts are converted to get the right debit/credit. + # If there is more than 1 debit and 1 credit, this can induce a rounding error, which we put in the foreign exchane gain/loss account. + if st_line_currency.id != company_currency.id: + diff_amount = bank_st_move_vals['debit'] - bank_st_move_vals['credit'] \ + + sum(aml['debit'] for aml in to_create) - sum(aml['credit'] for aml in to_create) + if not company_currency.is_zero(diff_amount): + diff_aml = self.get_currency_rate_line(cr, uid, st_line, diff_amount, move_id, context=context) + diff_aml['name'] = _('Rounding error from currency conversion') + to_create.append(diff_aml) # Create move lines move_line_pairs_to_reconcile = [] for mv_line_dict in to_create: From 4928db70adfc2f0811c5fcef3fdefc36565c0228 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Mon, 23 Feb 2015 15:27:45 +0100 Subject: [PATCH 5/9] [FIX] account: partner form buttons access rights When having account installed, but having as only access right "Contacts creation", it wasn't possible to display the partner form. Setting the "groups" on the button itself has as effect to hide the button, but not to prevent its value computation. If you did not had the access rights required to compute the buttons values, it leaded to security issues. Put the "groups" on the view instead prevent the button to be loaded, and its value to be computed. It therefore avoids both a useless computation (computing the value of a hidden button is not really useful), and prevent any access rights warnings. Besides, 3 different groups were needed to display the three buttons: - account.group_account_invoice - account.group_account_user - analytic.group_analytic_accounting Not having one of these tree groups could lead to security warnings. We therefore split this view into three sub-views, with each one a group set (and a button) opw-628668 --- addons/account/partner_view.xml | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/addons/account/partner_view.xml b/addons/account/partner_view.xml index 45d92f21d23..ebc485c5f76 100644 --- a/addons/account/partner_view.xml +++ b/addons/account/partner_view.xml @@ -70,6 +70,7 @@ res.partner + - + + + + + + partner.view.button.contracts_count + res.partner + + + + + From f23e47539e6a61e0f410787eb20a9adf2d186e57 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Mon, 23 Feb 2015 15:39:26 +0100 Subject: [PATCH 6/9] [FIX] project_issue: partner form issue button The reasons are similar than 4928db70adfc2f0811c5fcef3fdefc36565c0228 --- addons/project_issue/project_issue_view.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addons/project_issue/project_issue_view.xml b/addons/project_issue/project_issue_view.xml index 97f9c14294c..79a4072f2dd 100644 --- a/addons/project_issue/project_issue_view.xml +++ b/addons/project_issue/project_issue_view.xml @@ -368,12 +368,13 @@ res.partner + From 5ec8596f67990a52fb3427f31d86a5f2f36bc801 Mon Sep 17 00:00:00 2001 From: Raphael Collet Date: Mon, 23 Feb 2015 11:29:03 +0100 Subject: [PATCH 7/9] [FIX] fields: fix `_column.new()` by relying on `to_field_args()` The implementation was based on the ill-defined method `same_parameters()` that compares arguments based on a heuristic. Instead, we now create a new column and check whether it is equivalent to `self` by comparing the arguments returned by `to_field_args()`. If that is the case, `self` is reused instead of the new column. The code refactoring also fixes the column reuse which was broken by the introduction of the parameter `compute` in commit 9333c62. Indeed, with that parameter, `same_parameters()` always returned False, since old-api columns do not have that parameter by default. The parameter has been renamed to `_computed_field`, and is no longer passed for creating columns. --- openerp/fields.py | 3 +-- openerp/osv/fields.py | 33 +++++++++++++++------------------ 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/openerp/fields.py b/openerp/fields.py index 4e7129e9032..b78f5b330d2 100644 --- a/openerp/fields.py +++ b/openerp/fields.py @@ -658,7 +658,7 @@ class Field(object): self.column = fields.property(**args) elif self.column: # let the column provide a valid column for the given parameters - self.column = self.column.new(**args) + self.column = self.column.new(_computed_field=bool(self.compute), **args) else: # create a fresh new column of the right type self.column = getattr(fields, self.type)(**args) @@ -677,7 +677,6 @@ class Field(object): _column_groups = property(attrgetter('groups')) _column_change_default = property(attrgetter('change_default')) _column_deprecated = property(attrgetter('deprecated')) - _column_compute = property(lambda self: bool(self.compute)) ############################################################################ # diff --git a/openerp/osv/fields.py b/openerp/osv/fields.py index 852a8cbfa26..e99497e08dc 100644 --- a/openerp/osv/fields.py +++ b/openerp/osv/fields.py @@ -115,6 +115,7 @@ class _column(object): """ args0 = { 'string': string, + 'help': args.pop('help', None), 'required': required, 'readonly': readonly, '_domain': domain, @@ -127,6 +128,9 @@ class _column(object): 'translate': translate, 'select': select, 'manual': manual, + 'group_operator': args.pop('group_operator', None), + 'groups': args.pop('groups', None), + 'deprecated': args.pop('deprecated', None), } for key, val in args0.iteritems(): if val: @@ -140,30 +144,23 @@ class _column(object): if not self._classic_write or self.deprecated or self.manual: self._prefetch = False - def new(self, **args): - """ return a column like `self` with the given parameters """ + def new(self, _computed_field=False, **args): + """ Return a column like `self` with the given parameters; the parameter + `_computed_field` tells whether the corresponding field is computed. + """ # memory optimization: reuse self whenever possible; you can reduce the # average memory usage per registry by 10 megabytes! - return self if self.same_parameters(args) else type(self)(**args) - - def same_parameters(self, args): - dummy = object() - return all( - # either both are falsy, or they are equal - (not val1 and not val) or (val1 == val) - for key, val in args.iteritems() - for val1 in [getattr(self, key, getattr(self, '_' + key, dummy))] - ) + column = type(self)(**args) + return self if self.to_field_args() == column.to_field_args() else column def to_field(self): """ convert column `self` to a new-style field """ from openerp.fields import Field - return Field.by_type[self._type](**self.to_field_args()) + return Field.by_type[self._type](column=self, **self.to_field_args()) def to_field_args(self): """ return a dictionary with all the arguments to pass to the field """ base_items = [ - ('column', self), # field interfaces self ('copy', self.copy), ] truthy_items = filter(itemgetter(1), [ @@ -349,7 +346,7 @@ class float(_column): # synopsis: digits_compute(cr) -> (precision, scale) self.digits_compute = digits_compute - def new(self, **args): + def new(self, _computed_field=False, **args): # float columns are database-dependent, so always recreate them return type(self)(**args) @@ -1292,9 +1289,9 @@ class function(_column): self._symbol_f = type_class._symbol_f self._symbol_set = type_class._symbol_set - def new(self, **args): - if args.get('compute'): - # field is computed, we need an instance of the given type + def new(self, _computed_field=False, **args): + if _computed_field: + # field is computed, we need an instance of a non-function column type_class = globals()[self._type] return type_class(**args) else: From 7ffbb8d142f66f06efba6e9d0dc9cc522ccdb18e Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Mon, 23 Feb 2015 16:05:41 +0100 Subject: [PATCH 8/9] [FIX] project: task count button & link The tasks list view "act_project_project_2_project_task_all" always displays inactive tasks ("'active_test': False" in context). Both the link in the kanban and the button in the form leading to this list view should therefore counts both inactive & active tasks. opw-628672 --- addons/project/project.py | 2 +- addons/project/project_view.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/project/project.py b/addons/project/project.py index 7c25626c1fc..5e9f4b97200 100644 --- a/addons/project/project.py +++ b/addons/project/project.py @@ -188,7 +188,7 @@ class project(osv.osv): return res def _task_count(self, cr, uid, ids, field_name, arg, context=None): res={} - for tasks in self.browse(cr, uid, ids, context): + for tasks in self.browse(cr, uid, ids, dict(context, active_test=False)): res[tasks.id] = len(tasks.task_ids) return res def _get_alias_models(self, cr, uid, context=None): diff --git a/addons/project/project_view.xml b/addons/project/project_view.xml index f1b039ac222..d33214e204a 100644 --- a/addons/project/project_view.xml +++ b/addons/project/project_view.xml @@ -273,7 +273,7 @@
From a6a1764b2cdfc18dd6bc9718ccf431f0e0fe9b1f Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Mon, 23 Feb 2015 18:33:26 +0100 Subject: [PATCH 9/9] [FIX] models: initialize `_fields` attribute. Custom fields can point to custom models that have not been initialized yet (`_setup_base` not called). Ensure every models in the registry have a `_fields` attribute. Use a `frozendict` as a defensive check to ensure it wont be modified before calling `_setup_base`. --- openerp/models.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openerp/models.py b/openerp/models.py index 7dd628054a1..f8c4e5deb60 100644 --- a/openerp/models.py +++ b/openerp/models.py @@ -64,7 +64,7 @@ from .api import Environment from .exceptions import except_orm, AccessError, MissingError, ValidationError from .osv import fields from .osv.query import Query -from .tools import lazy_property, ormcache +from .tools import frozendict, lazy_property, ormcache from .tools.config import config from .tools.misc import CountingStream, DEFAULT_SERVER_DATETIME_FORMAT, DEFAULT_SERVER_DATE_FORMAT from .tools.safe_eval import safe_eval as eval @@ -638,6 +638,7 @@ class BaseModel(object): '_register': False, '_columns': None, # recomputed in _setup_fields() '_defaults': None, # recomputed in _setup_base() + '_fields': frozendict(), # idem '_inherits': dict(cls._inherits), '_depends': dict(cls._depends), '_constraints': list(cls._constraints),