From b8b89bf47d7a15a467ec322723b297ef6fa774af Mon Sep 17 00:00:00 2001 From: Julien Castiaux Date: Mon, 6 Sep 2021 09:56:40 +0000 Subject: [PATCH] [FIX] core: prevent redundant default on related Setting a default value on a readonly related field without an inverse method is nonsense. We log some warning when it happens. We also fixed other cases where a related field has a default value that overrides the target field's value. closes odoo/odoo#67762 Related: odoo/enterprise#17313 Signed-off-by: Julien Castiaux --- addons/account/models/account_bank_statement.py | 3 +-- addons/account/models/account_move.py | 2 +- addons/account/models/account_reconcile_model.py | 2 +- addons/hr_expense/models/hr_expense.py | 2 +- addons/hr_holidays/models/hr_leave.py | 2 +- addons/purchase_requisition/models/purchase_requisition.py | 2 +- addons/sale/models/sale_order_line.py | 2 +- addons/stock/models/stock_move_line.py | 2 +- odoo/fields.py | 5 +++++ 9 files changed, 13 insertions(+), 9 deletions(-) diff --git a/addons/account/models/account_bank_statement.py b/addons/account/models/account_bank_statement.py index 9f8efc0f6ec..a6a37853b38 100644 --- a/addons/account/models/account_bank_statement.py +++ b/addons/account/models/account_bank_statement.py @@ -223,8 +223,7 @@ class AccountBankStatement(models.Model): currency_id = fields.Many2one('res.currency', compute='_compute_currency', string="Currency") journal_id = fields.Many2one('account.journal', string='Journal', required=True, states={'confirm': [('readonly', True)]}, default=_default_journal, check_company=True) journal_type = fields.Selection(related='journal_id.type', help="Technical field used for usability purposes") - company_id = fields.Many2one('res.company', related='journal_id.company_id', string='Company', store=True, readonly=True, - default=lambda self: self.env.company) + company_id = fields.Many2one('res.company', related='journal_id.company_id', string='Company', store=True, readonly=True) total_entry_encoding = fields.Monetary('Transactions Subtotal', compute='_end_balance', store=True, help="Total of transaction lines.") balance_end = fields.Monetary('Computed Balance', compute='_end_balance', store=True, help='Balance as calculated based on Opening Balance and transaction lines') diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py index ce9d193bf96..b2278d1102e 100644 --- a/addons/account/models/account_move.py +++ b/addons/account/models/account_move.py @@ -3410,7 +3410,7 @@ class AccountMoveLine(models.Model): ref = fields.Char(related='move_id.ref', store=True, copy=False, index=True, readonly=False) parent_state = fields.Selection(related='move_id.state', store=True, readonly=True) journal_id = fields.Many2one(related='move_id.journal_id', store=True, index=True, copy=False) - company_id = fields.Many2one(related='move_id.company_id', store=True, readonly=True, default=lambda self: self.env.company) + company_id = fields.Many2one(related='move_id.company_id', store=True, readonly=True) company_currency_id = fields.Many2one(related='company_id.currency_id', string='Company Currency', readonly=True, store=True, help='Utility field to express amount currency') diff --git a/addons/account/models/account_reconcile_model.py b/addons/account/models/account_reconcile_model.py index 9a2c4014a2d..be34f6caa7b 100644 --- a/addons/account/models/account_reconcile_model.py +++ b/addons/account/models/account_reconcile_model.py @@ -46,7 +46,7 @@ class AccountReconcileModelLine(models.Model): allow_payment_tolerance = fields.Boolean(related='model_id.allow_payment_tolerance') payment_tolerance_param = fields.Float(related='model_id.payment_tolerance_param') rule_type = fields.Selection(related='model_id.rule_type') - company_id = fields.Many2one(related='model_id.company_id', store=True, default=lambda self: self.env.company) + company_id = fields.Many2one(related='model_id.company_id', store=True) sequence = fields.Integer(required=True, default=10) account_id = fields.Many2one('account.account', string='Account', ondelete='cascade', domain="[('deprecated', '=', False), ('company_id', '=', company_id), ('is_off_balance', '=', False)]", diff --git a/addons/hr_expense/models/hr_expense.py b/addons/hr_expense/models/hr_expense.py index 5ef8984c873..65b446f4815 100644 --- a/addons/hr_expense/models/hr_expense.py +++ b/addons/hr_expense/models/hr_expense.py @@ -861,7 +861,7 @@ class HrExpenseSheet(models.Model): store=True, readonly=True, copy=False, tracking=True, compute='_compute_payment_state') employee_id = fields.Many2one('hr.employee', string="Employee", required=True, readonly=True, tracking=True, states={'draft': [('readonly', False)]}, default=_default_employee_id, check_company=True, domain= lambda self: self.env['hr.expense']._get_employee_id_domain()) address_id = fields.Many2one('res.partner', compute='_compute_from_employee_id', store=True, readonly=False, copy=True, string="Employee Home Address", check_company=True) - payment_mode = fields.Selection(related='expense_line_ids.payment_mode', default='own_account', readonly=True, string="Paid By", tracking=True) + payment_mode = fields.Selection(related='expense_line_ids.payment_mode', readonly=True, string="Paid By", tracking=True) user_id = fields.Many2one('res.users', 'Manager', compute='_compute_from_employee_id', store=True, readonly=True, copy=False, states={'draft': [('readonly', False)]}, tracking=True, domain=lambda self: [('groups_id', 'in', self.env.ref('hr_expense.group_hr_expense_team_approver').id)]) total_amount = fields.Monetary('Total Amount', currency_field='currency_id', compute='_compute_amount', store=True, tracking=True) amount_residual = fields.Monetary( diff --git a/addons/hr_holidays/models/hr_leave.py b/addons/hr_holidays/models/hr_leave.py index 11f417456a6..bd7a0f49c49 100644 --- a/addons/hr_holidays/models/hr_leave.py +++ b/addons/hr_holidays/models/hr_leave.py @@ -122,7 +122,7 @@ class HolidaysRequest(models.Model): "\nThe status is 'Refused', when time off request is refused by manager." + "\nThe status is 'Approved', when time off request is approved by manager.") report_note = fields.Text('HR Comments', copy=False, groups="hr_holidays.group_hr_holidays_manager") - user_id = fields.Many2one('res.users', string='User', related='employee_id.user_id', related_sudo=True, compute_sudo=True, store=True, default=lambda self: self.env.uid, readonly=True) + user_id = fields.Many2one('res.users', string='User', related='employee_id.user_id', related_sudo=True, compute_sudo=True, store=True, readonly=True) manager_id = fields.Many2one('hr.employee', compute='_compute_from_employee_id', store=True, readonly=False) # leave type configuration holiday_status_id = fields.Many2one( diff --git a/addons/purchase_requisition/models/purchase_requisition.py b/addons/purchase_requisition/models/purchase_requisition.py index 4daa779f499..7f93babe51d 100644 --- a/addons/purchase_requisition/models/purchase_requisition.py +++ b/addons/purchase_requisition/models/purchase_requisition.py @@ -177,7 +177,7 @@ class PurchaseRequisitionLine(models.Model): price_unit = fields.Float(string='Unit Price', digits='Product Price') qty_ordered = fields.Float(compute='_compute_ordered_qty', string='Ordered Quantities') requisition_id = fields.Many2one('purchase.requisition', required=True, string='Purchase Agreement', ondelete='cascade') - company_id = fields.Many2one('res.company', related='requisition_id.company_id', string='Company', store=True, readonly=True, default= lambda self: self.env.company) + company_id = fields.Many2one('res.company', related='requisition_id.company_id', string='Company', store=True, readonly=True) account_analytic_id = fields.Many2one('account.analytic.account', string='Analytic Account') analytic_tag_ids = fields.Many2many('account.analytic.tag', string='Analytic Tags') schedule_date = fields.Date(string='Scheduled Date') diff --git a/addons/sale/models/sale_order_line.py b/addons/sale/models/sale_order_line.py index f4b09f1dc19..449594da2a1 100644 --- a/addons/sale/models/sale_order_line.py +++ b/addons/sale/models/sale_order_line.py @@ -301,7 +301,7 @@ class SaleOrderLine(models.Model): " They are not copied when duplicating a sales order.") state = fields.Selection( - related='order_id.state', string='Order Status', copy=False, store=True, default='draft') + related='order_id.state', string='Order Status', copy=False, store=True) customer_lead = fields.Float( 'Lead Time', required=True, default=0.0, diff --git a/addons/stock/models/stock_move_line.py b/addons/stock/models/stock_move_line.py index a0b287fccc6..17eca8cff00 100644 --- a/addons/stock/models/stock_move_line.py +++ b/addons/stock/models/stock_move_line.py @@ -68,7 +68,7 @@ class StockMoveLine(models.Model): state = fields.Selection(related='move_id.state', store=True, related_sudo=False) is_initial_demand_editable = fields.Boolean(related='move_id.is_initial_demand_editable') is_inventory = fields.Boolean(related='move_id.is_inventory') - is_locked = fields.Boolean(related='move_id.is_locked', default=True, readonly=True) + is_locked = fields.Boolean(related='move_id.is_locked', readonly=True) consume_line_ids = fields.Many2many('stock.move.line', 'stock_move_line_consume_rel', 'consume_line_id', 'produce_line_id', help="Technical link to see who consumed what. ") produce_line_ids = fields.Many2many('stock.move.line', 'stock_move_line_consume_rel', 'produce_line_id', 'consume_line_id', help="Technical link to see which line was produced with this. ") reference = fields.Char(related='move_id.reference', store=True, related_sudo=False, readonly=False) diff --git a/odoo/fields.py b/odoo/fields.py index 1ba2fb16d66..c6b3ef25f76 100644 --- a/odoo/fields.py +++ b/odoo/fields.py @@ -547,6 +547,11 @@ class Field(MetaField('DummyField', (object,), {})): # allow searching on self only if the related field is searchable self.search = self._search_related + # A readonly related field without an inverse method should not have a + # default value, as it does not make sense. + if self.default and self.readonly and not self.inverse: + _logger.warning("Redundant default on %s", self) + # copy attributes from field to self (string, help, etc.) for attr, prop in self.related_attrs: if not getattr(self, attr):