From 7ad9487a83539d13fcbaccf605e3b0180280fd2d Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Thu, 1 Sep 2016 13:14:53 +0200 Subject: [PATCH 1/8] [IMP] account: remove required attribute on stored and related field The field journal_id and date are both required on account.move and are stored related on account.move.line. Setting the required on the account.move.line allows to make it required in the views or for the ORM but in practice it will be same as it's required on the parent. Making it required is a performance killer as it forces to specify a value for the create which will retrigger an update on the parent move. This means that adding a line with a date value on an account.move with already 10 lines will trigger 11 updates (date of the new line -> date of the move -> date on the 10 existing lines), even if the value has not changed. --- addons/account/models/account_move.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py index 0470655af7b..91537199ad1 100644 --- a/addons/account/models/account_move.py +++ b/addons/account/models/account_move.py @@ -395,12 +395,12 @@ class AccountMoveLine(models.Model): matched_credit_ids = fields.One2many('account.partial.reconcile', 'debit_move_id', String='Matched Credits', help='Credit journal items that are matched with this journal item.') journal_id = fields.Many2one('account.journal', related='move_id.journal_id', string='Journal', - default=_get_journal, required=True, index=True, store=True, copy=False) + default=_get_journal, index=True, store=True, copy=False) # related is required blocked = fields.Boolean(string='No Follow-up', default=False, help="You can check this box to mark this journal item as a litigation with the associated partner") date_maturity = fields.Date(string='Due date', index=True, required=True, help="This field is used for payable and receivable journal entries. You can put the limit date for the payment of this line.") - date = fields.Date(related='move_id.date', string='Date', required=True, index=True, default=fields.Date.context_today, store=True, copy=False) + date = fields.Date(related='move_id.date', string='Date', index=True, store=True, copy=False) # related is required analytic_line_ids = fields.One2many('account.analytic.line', 'move_id', string='Analytic lines', oldname="analytic_lines") tax_ids = fields.Many2many('account.tax', string='Taxes') tax_line_id = fields.Many2one('account.tax', string='Originator tax', ondelete='restrict') From fe2c11f397c17587be3c587ba3f46a35455683e4 Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Thu, 1 Sep 2016 13:23:35 +0200 Subject: [PATCH 2/8] [IMP] account: clean create method from mandatory variable Avoid setting a value for a related field as it will trigger onchange update. This code was relevant when the date was different on the move and the line but is no longer needed. Remove all the `if vals.get(mandatory_field)` to simplify this method and remove dead code or condition always true. --- addons/account/models/account_move.py | 100 ++++++++------------------ 1 file changed, 30 insertions(+), 70 deletions(-) diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py index 91537199ad1..4967d33036c 100644 --- a/addons/account/models/account_move.py +++ b/addons/account/models/account_move.py @@ -319,24 +319,6 @@ class AccountMoveLine(models.Model): currency = self.env['account.journal'].browse(context['default_journal_id']).currency_id return currency - @api.model - def _get_journal(self): - """ Return journal based on the journal type """ - context = dict(self._context or {}) - journal_id = context.get('journal_id', False) - if journal_id: - return journal_id - - journal_type = context.get('journal_type', False) - if journal_type: - recs = self.env['account.journal'].search([('type', '=', journal_type)]) - if not recs: - action = self.env.ref('account.action_account_journal_form') - msg = _("""Cannot find any account journal of "%s" type for this company, You should create one.\n Please go to Journal Configuration""") % journal_type.replace('_', ' ').title() - raise RedirectWarning(msg, action.id, _('Go to the configuration panel')) - journal_id = recs[0].id - return journal_id - @api.depends('debit', 'credit', 'move_id.matched_percentage', 'move_id.journal_id') def _compute_cash_basis(self): for move_line in self: @@ -395,7 +377,7 @@ class AccountMoveLine(models.Model): matched_credit_ids = fields.One2many('account.partial.reconcile', 'debit_move_id', String='Matched Credits', help='Credit journal items that are matched with this journal item.') journal_id = fields.Many2one('account.journal', related='move_id.journal_id', string='Journal', - default=_get_journal, index=True, store=True, copy=False) # related is required + index=True, store=True, copy=False) # related is required blocked = fields.Boolean(string='No Follow-up', default=False, help="You can check this box to mark this journal item as a litigation with the associated partner") date_maturity = fields.Date(string='Due date', index=True, required=True, @@ -1017,71 +999,50 @@ class AccountMoveLine(models.Model): debit-credit == 0 while creating the move lines composing the move. """ - AccountObj = self.env['account.account'] - MoveObj = self.env['account.move'] context = dict(self._context or {}) amount = vals.get('debit', 0.0) - vals.get('credit', 0.0) if not vals.get('partner_id') and context.get('partner_id'): vals['partner_id'] = context.get('partner_id') - if vals.get('move_id', False): - move = MoveObj.browse(vals['move_id']) - if move.date and not vals.get('date'): - vals['date'] = move.date - if ('account_id' in vals) and AccountObj.browse(vals['account_id']).deprecated: + move = self.env['account.move'].browse(vals['move_id']) + account = self.env['account.account'].browse(vals['account_id']) + if account.deprecated: raise UserError(_('You cannot use deprecated account.')) if 'journal_id' in vals and vals['journal_id']: context['journal_id'] = vals['journal_id'] if 'date' in vals and vals['date']: context['date'] = vals['date'] - if ('journal_id' not in context) and ('move_id' in vals) and vals['move_id']: - m = MoveObj.browse(vals['move_id']) - context['journal_id'] = m.journal_id.id - context['date'] = m.date + if 'journal_id' not in context: + context['journal_id'] = move.journal_id.id + context['date'] = move.date #we need to treat the case where a value is given in the context for period_id as a string if not context.get('journal_id', False) and context.get('search_default_journal_id', False): context['journal_id'] = context.get('search_default_journal_id') if 'date' not in context: context['date'] = fields.Date.context_today(self) - move_id = vals.get('move_id', False) - journal = self.env['account.journal'].browse(context['journal_id']) - vals['journal_id'] = vals.get('journal_id') or context.get('journal_id') - vals['date'] = vals.get('date') or context.get('date') - vals['date_maturity'] = vals.get('date_maturity') if vals.get('date_maturity') else vals['date'] - if not move_id: - if not vals.get('move_id', False): - if journal.sequence_id: - v = { - 'date': vals.get('date', time.strftime('%Y-%m-%d')), - 'journal_id': context['journal_id'] - } - if vals.get('ref', ''): - v.update({'ref': vals['ref']}) - move_id = MoveObj.with_context(context).create(v) - vals['move_id'] = move_id.id - else: - raise UserError(_('Cannot create an automatic sequence for this piece.\nPut a sequence in the journal definition for automatic numbering or create a sequence manually for this piece.')) + journal = vals.get('journal_id') and self.env['account.journal'].browse(vals['journal_id']) or move.journal_id + vals['date_maturity'] = vals.get('date_maturity') or vals.get('date') or move.date ok = not (journal.type_control_ids or journal.account_control_ids) - if ('account_id' in vals): - account = AccountObj.browse(vals['account_id']) - if journal.type_control_ids: - type = account.user_type_id - for t in journal.type_control_ids: - if type == t: - ok = True - break - if journal.account_control_ids and not ok: - for a in journal.account_control_ids: - if a.id == vals['account_id']: - ok = True - break - # Automatically convert in the account's secondary currency if there is one and - # the provided values were not already multi-currency - if account.currency_id and 'amount_currency' not in vals and account.currency_id.id != account.company_id.currency_id.id: - vals['currency_id'] = account.currency_id.id - ctx = {} - if 'date' in vals: - ctx['date'] = vals['date'] - vals['amount_currency'] = account.company_id.currency_id.with_context(ctx).compute(amount, account.currency_id) + + if journal.type_control_ids: + type = account.user_type_id + for t in journal.type_control_ids: + if type == t: + ok = True + break + if journal.account_control_ids and not ok: + for a in journal.account_control_ids: + if a.id == vals['account_id']: + ok = True + break + # Automatically convert in the account's secondary currency if there is one and + # the provided values were not already multi-currency + if account.currency_id and 'amount_currency' not in vals and account.currency_id.id != account.company_id.currency_id.id: + vals['currency_id'] = account.currency_id.id + ctx = {} + if 'date' in vals: + ctx['date'] = vals['date'] + vals['amount_currency'] = account.company_id.currency_id.with_context(ctx).compute(amount, account.currency_id) + if not ok: raise UserError(_('You cannot use this general account in this journal, check the tab \'Entry Controls\' on the related journal.')) @@ -1132,7 +1093,6 @@ class AccountMoveLine(models.Model): self.with_context(context).create(tax_line_vals) if self._context.get('check_move_validity', True): - move = MoveObj.browse(vals['move_id']) move.with_context(context)._post_validate() return new_line From caeff5711b0afa505791ed6ae4472d1e8c2c59e6 Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Thu, 1 Sep 2016 16:20:10 +0200 Subject: [PATCH 3/8] [FIX] hr_expense: do not not update related field journal_id is a related field that was set just before --- addons/hr_expense/models/hr_expense.py | 1 - 1 file changed, 1 deletion(-) diff --git a/addons/hr_expense/models/hr_expense.py b/addons/hr_expense/models/hr_expense.py index c3f9daf30a4..b492f105319 100644 --- a/addons/hr_expense/models/hr_expense.py +++ b/addons/hr_expense/models/hr_expense.py @@ -125,7 +125,6 @@ class HrExpense(models.Model): 'date_maturity': line.get('date_maturity'), 'partner_id': partner_id, 'name': line['name'][:64], - 'date': self.sheet_id.accounting_date, 'debit': line['price'] > 0 and line['price'], 'credit': line['price'] < 0 and - line['price'], 'account_id': line['account_id'], From c368f7dd21f1ff8ba2e0a2f87d84a87392b8072d Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Thu, 1 Sep 2016 16:29:49 +0200 Subject: [PATCH 4/8] [FIX] base,hr_expense: unrequire computed field Which does not make sense. it's the computation that should set the value. Also the default is no longer needed. --- addons/hr_expense/models/hr_expense.py | 2 +- openerp/addons/base/ir/ir_sequence.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/addons/hr_expense/models/hr_expense.py b/addons/hr_expense/models/hr_expense.py index b492f105319..db654367bc7 100644 --- a/addons/hr_expense/models/hr_expense.py +++ b/addons/hr_expense/models/hr_expense.py @@ -39,7 +39,7 @@ class HrExpense(models.Model): ('reported', 'Reported'), ('done', 'Posted'), ('refused', 'Refused') - ], compute='_compute_state', string='Status', copy=False, default="draft", index=True, readonly=True, required=True, store=True, + ], compute='_compute_state', string='Status', copy=False, index=True, readonly=True, store=True, help="Status of the expense.") sheet_id = fields.Many2one('hr.expense.sheet', string="Expense Report", readonly=True, copy=False) reference = fields.Char(string="Bill Reference") diff --git a/openerp/addons/base/ir/ir_sequence.py b/openerp/addons/base/ir/ir_sequence.py index 28dd8cb1857..cb67a6f7fc9 100644 --- a/openerp/addons/base/ir/ir_sequence.py +++ b/openerp/addons/base/ir/ir_sequence.py @@ -99,7 +99,7 @@ class IrSequence(models.Model): suffix = fields.Char(help="Suffix value of the record for the sequence") number_next = fields.Integer(string='Next Number', required=True, default=1, help="Next number of this sequence") number_next_actual = fields.Integer(compute='_get_number_next_actual', inverse='_set_number_next_actual', - required=True, string='Next Number', default=1, + string='Next Number', help="Next number that will be used. This number can be incremented " "frequently so the displayed value might already be obsolete") number_increment = fields.Integer(string='Step', required=True, default=1, @@ -310,7 +310,7 @@ class IrSequenceDateRange(models.Model): sequence_id = fields.Many2one("ir.sequence", string='Main Sequence', required=True, ondelete='cascade') number_next = fields.Integer(string='Next Number', required=True, default=1, help="Next number of this sequence") number_next_actual = fields.Integer(compute='_get_number_next_actual', inverse='_set_number_next_actual', - required=True, string='Next Number', default=1, + string='Next Number', help="Next number that will be used. This number can be incremented " "frequently so the displayed value might already be obsolete") From 2293c2fe1a1794511db2f75588b5bd536a551964 Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Fri, 2 Sep 2016 10:05:57 +0200 Subject: [PATCH 5/8] [FIX] hr_expense: do not write on related field ref is a related set on the account.move. Writting on the line set the same reference for all the lines and the parent move (the one of the last line). Instead put it on the move if there is only one reference or do not put a wrong one if we can't determine one. --- addons/hr_expense/models/hr_expense.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/addons/hr_expense/models/hr_expense.py b/addons/hr_expense/models/hr_expense.py index db654367bc7..5d1394d2996 100644 --- a/addons/hr_expense/models/hr_expense.py +++ b/addons/hr_expense/models/hr_expense.py @@ -132,7 +132,6 @@ class HrExpense(models.Model): 'amount_currency': line['price'] > 0 and abs(line.get('amount_currency')) or - abs(line.get('amount_currency')), 'currency_id': line.get('currency_id'), 'tax_line_id': line.get('tax_line_id'), - 'ref': line.get('ref'), 'quantity': line.get('quantity', 1.00), 'product_id': line.get('product_id'), 'product_uom_id': line.get('uom_id'), @@ -175,15 +174,18 @@ class HrExpense(models.Model): for expense in self: acc_date = expense.sheet_id.accounting_date or fields.Date.context_today(self) jrn = expense.sheet_id.bank_journal_id if expense.payment_mode == 'company_account' else expense.sheet_id.journal_id - journal_dict.setdefault(jrn, []) - journal_dict[jrn].append(expense) + journal_dict.setdefault(jrn, self.env['hr.expense']) + journal_dict[jrn] |= expense for journal, expense_list in journal_dict.items(): #create the move that will contain the accounting entries + # reference if the same for every expense + ref = len(expense_list.mapped('employee_id.address_home_id.ref')) == 1 and expense_list[0].employee_id.address_home_id.ref or False move = self.env['account.move'].create({ 'journal_id': journal.id, 'company_id': self.env.user.company_id.id, 'date': acc_date, + 'ref': ref }) for expense in expense_list: company_currency = expense.company_id.currency_id @@ -210,7 +212,6 @@ class HrExpense(models.Model): 'date_maturity': acc_date, 'amount_currency': diff_currency_p and total_currency or False, 'currency_id': diff_currency_p and expense.currency_id.id or False, - 'ref': expense.employee_id.address_home_id.ref or False }) #convert eml into an osv-valid format From d676f2a46f1a020a22232e3c73135ed0ba83631d Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Fri, 2 Sep 2016 10:07:57 +0200 Subject: [PATCH 6/8] [FIX] account: avoid updating related field The account.move has already self.date for the date field (cf the method `_prepare_reconciliation_move`). As the field date on the account.move.line is a related, it makes useless updates to write it here. Same issue for journal_id field --- addons/account/models/account_bank_statement.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/addons/account/models/account_bank_statement.py b/addons/account/models/account_bank_statement.py index 37b16a8ae19..673bbc6d6b6 100644 --- a/addons/account/models/account_bank_statement.py +++ b/addons/account/models/account_bank_statement.py @@ -782,7 +782,6 @@ class AccountBankStatementLine(models.Model): amount_currency = self.amount_currency * ratio return { 'name': self.name, - 'date': self.date, 'move_id': move.id, 'partner_id': self.partner_id and self.partner_id.id or False, 'account_id': amount >= 0 \ @@ -791,7 +790,6 @@ class AccountBankStatementLine(models.Model): 'credit': amount < 0 and -amount or 0.0, 'debit': amount > 0 and amount or 0.0, 'statement_id': self.statement_id.id, - 'journal_id': self.statement_id.journal_id.id, 'currency_id': statement_currency != company_currency and statement_currency.id or (st_line_currency != company_currency and st_line_currency.id or False), 'amount_currency': amount_currency, } From 583e92b18ef2cae824a5861b3472e65ac0efb5dc Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Fri, 2 Sep 2016 10:39:14 +0200 Subject: [PATCH 7/8] [FIX] remove default attribute on computed field Which is useless when there is no inverse method --- addons/account/models/account_move.py | 10 ++++++---- addons/hr_attendance/models/hr_employee.py | 2 +- addons/hr_timesheet/project_timesheet.py | 2 +- addons/lunch/models/lunch.py | 2 +- addons/sale/models/sale.py | 6 +++--- 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py index 4967d33036c..2b82cef6c85 100644 --- a/addons/account/models/account_move.py +++ b/addons/account/models/account_move.py @@ -348,10 +348,12 @@ class AccountMoveLine(models.Model): product_id = fields.Many2one('product.product', string='Product') debit = fields.Monetary(default=0.0, currency_field='company_currency_id') credit = fields.Monetary(default=0.0, currency_field='company_currency_id') - balance = fields.Monetary(compute='_store_balance', store=True, currency_field='company_currency_id', default=0.0, help="Technical field holding the debit - credit in order to open meaningful graph views from reports") - debit_cash_basis = fields.Monetary(currency_field='company_currency_id', default=0.0, compute='_compute_cash_basis', store=True) - credit_cash_basis = fields.Monetary(currency_field='company_currency_id', default=0.0, compute='_compute_cash_basis', store=True) - balance_cash_basis = fields.Monetary(compute='_compute_cash_basis', store=True, currency_field='company_currency_id', default=0.0, help="Technical field holding the debit_cash_basis - credit_cash_basis in order to open meaningful graph views from reports") + balance = fields.Monetary(compute='_store_balance', store=True, currency_field='company_currency_id', + help="Technical field holding the debit - credit in order to open meaningful graph views from reports") + debit_cash_basis = fields.Monetary(currency_field='company_currency_id', compute='_compute_cash_basis', store=True) + credit_cash_basis = fields.Monetary(currency_field='company_currency_id', compute='_compute_cash_basis', store=True) + balance_cash_basis = fields.Monetary(compute='_compute_cash_basis', store=True, currency_field='company_currency_id', + help="Technical field holding the debit_cash_basis - credit_cash_basis in order to open meaningful graph views from reports") amount_currency = fields.Monetary(default=0.0, help="The amount expressed in an optional other currency if it is a multi-currency entry.") company_currency_id = fields.Many2one('res.currency', related='company_id.currency_id', string="Company Currency", readonly=True, help='Utility field to express amount currency', store=True) diff --git a/addons/hr_attendance/models/hr_employee.py b/addons/hr_attendance/models/hr_employee.py index 2a5a66d838f..88b5db50ee8 100644 --- a/addons/hr_attendance/models/hr_employee.py +++ b/addons/hr_attendance/models/hr_employee.py @@ -27,7 +27,7 @@ class HrEmployee(models.Model): last_attendance_id = fields.Many2one('hr.attendance', compute='_compute_last_attendance_id') attendance_state = fields.Selection(string="Attendance", compute='_compute_attendance_state', selection=[('checked_out', "Checked out"), ('checked_in', "Checked in")]) manual_attendance = fields.Boolean(string='Manual Attendance', compute='_compute_manual_attendance', inverse='_inverse_manual_attendance', - help='The employee will have access to the "My Attendances" menu to perform his check in and out from his session', default=False) + help='The employee will have access to the "My Attendances" menu to perform his check in and out from his session') _sql_constraints = [('barcode_uniq', 'unique (barcode)', "The Badge ID must be unique, this one is already assigned to another employee.")] diff --git a/addons/hr_timesheet/project_timesheet.py b/addons/hr_timesheet/project_timesheet.py index b3b50b32d51..f82ca0cb1f3 100644 --- a/addons/hr_timesheet/project_timesheet.py +++ b/addons/hr_timesheet/project_timesheet.py @@ -48,7 +48,7 @@ class Task(models.Model): effective_hours = fields.Float(compute='_hours_get', store=True, string='Hours Spent', help="Computed using the sum of the task work done.") total_hours = fields.Float(compute='_hours_get', store=True, string='Total', help="Computed as: Time Spent + Remaining Time.") total_hours_spent = fields.Float(compute='_hours_get', store=True, string='Total Hours', help="Computed as: Time Spent + Sub-tasks Hours.") - progress = fields.Float(compute='_hours_get', store=True, string='Working Time Recorded', group_operator="avg", default=0.0) + progress = fields.Float(compute='_hours_get', store=True, string='Working Time Recorded', group_operator="avg") delay_hours = fields.Float(compute='_hours_get', store=True, string='Delay Hours', help="Computed as difference between planned hours by the project manager and the total hours of the task.") children_hours = fields.Float(compute='_hours_get', store=True, string='Sub-tasks Hours', help="Sum of the planned hours of all sub-tasks (when a sub-task is closed or its spent hours exceed its planned hours, spent hours are counted instead)") timesheet_ids = fields.One2many('account.analytic.line', 'task_id', 'Timesheets') diff --git a/addons/lunch/models/lunch.py b/addons/lunch/models/lunch.py index 7cc750fb349..87524b3872d 100644 --- a/addons/lunch/models/lunch.py +++ b/addons/lunch/models/lunch.py @@ -39,7 +39,7 @@ class LunchOrder(models.Model): state = fields.Selection([('new', 'New'), ('confirmed', 'Received'), ('cancelled', 'Cancelled')], - 'Status', readonly=True, index=True, copy=False, default='new', + 'Status', readonly=True, index=True, copy=False, compute='_compute_order_state', store=True) alerts = fields.Text(compute='_compute_alerts_get', string="Alerts") previous_order_ids = fields.Many2many('lunch.order.line', compute='_compute_previous_order_ids', diff --git a/addons/sale/models/sale.py b/addons/sale/models/sale.py index a26b64eae66..b9da002bff1 100644 --- a/addons/sale/models/sale.py +++ b/addons/sale/models/sale.py @@ -134,7 +134,7 @@ class SaleOrder(models.Model): ('invoiced', 'Fully Invoiced'), ('to invoice', 'To Invoice'), ('no', 'Nothing to Invoice') - ], string='Invoice Status', compute='_get_invoiced', store=True, readonly=True, default='no') + ], string='Invoice Status', compute='_get_invoiced', store=True, readonly=True) note = fields.Text('Terms and conditions', default=_default_note) @@ -741,10 +741,10 @@ class SaleOrderLine(models.Model): qty_delivered = fields.Float(string='Delivered', copy=False, digits=dp.get_precision('Product Unit of Measure'), default=0.0) qty_to_invoice = fields.Float( compute='_get_to_invoice_qty', string='To Invoice', store=True, readonly=True, - digits=dp.get_precision('Product Unit of Measure'), default=0.0) + digits=dp.get_precision('Product Unit of Measure')) qty_invoiced = fields.Float( compute='_get_invoice_qty', string='Invoiced', store=True, readonly=True, - digits=dp.get_precision('Product Unit of Measure'), default=0.0) + digits=dp.get_precision('Product Unit of Measure')) salesman_id = fields.Many2one(related='order_id.user_id', store=True, string='Salesperson', readonly=True) currency_id = fields.Many2one(related='order_id.currency_id', store=True, string='Currency', readonly=True) From 80aa17aac79f19cfb488998451c2cd536c00645e Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Fri, 2 Sep 2016 10:39:56 +0200 Subject: [PATCH 8/8] [FIX] note: properly set the default method stage_id is comptued and based on stage_ids The default value should be put on stage_ids, not stage_id, it has the same effect but avoids an unecessary chain update. --- addons/note/models/note.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/addons/note/models/note.py b/addons/note/models/note.py index e6dba8a8777..439722d13ee 100644 --- a/addons/note/models/note.py +++ b/addons/note/models/note.py @@ -45,8 +45,9 @@ class Note(models.Model): memo = fields.Html('Note Content') sequence = fields.Integer('Sequence') stage_id = fields.Many2one('note.stage', compute='_compute_stage_id', - inverse='_inverse_stage_id', default=_get_default_stage_id, string='Stage') - stage_ids = fields.Many2many('note.stage', 'note_stage_rel', 'note_id', 'stage_id', string='Stages of Users') + inverse='_inverse_stage_id', string='Stage') + stage_ids = fields.Many2many('note.stage', 'note_stage_rel', 'note_id', 'stage_id', + string='Stages of Users', default=_get_default_stage_id) open = fields.Boolean(string='Active', track_visibility='onchange', default=True) date_done = fields.Date('Date done') color = fields.Integer(string='Color Index')