From 75a105f46a13f75eb56a0de80faa2a6e146730aa Mon Sep 17 00:00:00 2001 From: Gorash Date: Tue, 28 Mar 2023 08:20:04 +0000 Subject: [PATCH] [REF] base/all: Update modifier syntax: remove 'states' from fields These changes are made as a result of simplifying attrs and 'states' in views. However, they should have remained in a separate commit. When applying the script making the xml changes (used later for the migration script), the script checked the definition of the python fields in order to convert the information into a python expression. Therefore, this commit is not applied when the script is applied to xml changes. During this attribute deletion pre-existing errors were found. Part of the code was using the boolean values of 'states' and another part of the code was not. The behavior could therefore be different (in cases where readonly on the field had the same value as the ballan in 'states'). Following the deletion of 'states' and without the application of the view migration, the js tests (tower) were no longer functional. Tests using the Form view suffered the same effect. There are few tests that had to be adapted, including two tests in business accounting (updated by the accounting team). A test for column_invisible did not work. Test checking if the test system triggers an error if we try to write on an invisible field. It turns out that Form was testing on the value of invisible but not taking into account if the column was invisible. The test system fix is applied separately because there were a lot of tests that were incorrect. Part-of: odoo/odoo#104741 --- addons/account/models/account_move.py | 19 +---------- addons/event/models/event_registration.py | 8 ++--- addons/event_booth_sale/models/event_booth.py | 2 +- addons/hr_expense/models/hr_expense.py | 32 ++++++++----------- addons/hr_holidays/models/hr_leave.py | 23 +++++-------- .../hr_holidays/models/hr_leave_allocation.py | 30 +++++++---------- addons/l10n_ar/models/account_move.py | 4 +-- addons/l10n_id_efaktur/models/account_move.py | 2 +- addons/l10n_in/models/account_invoice.py | 8 ++--- .../l10n_in_purchase/models/purchase_order.py | 2 +- addons/l10n_in_sale/models/sale_order.py | 4 +-- addons/l10n_it_edi/models/account_invoice.py | 4 +-- .../models/account_payment.py | 5 +-- .../models/account_move.py | 5 ++- addons/lunch/models/lunch_order.py | 6 ++-- addons/mail/models/fetchmail.py | 10 +++--- addons/mass_mailing/models/mailing.py | 8 ++--- addons/mrp/models/mrp_production.py | 7 ++-- addons/mrp/models/mrp_unbuild.py | 19 ++++++----- addons/mrp/models/mrp_workorder.py | 9 ++---- addons/mrp/models/stock_scrap.py | 5 ++- .../models/stock_landed_cost.py | 2 +- addons/point_of_sale/models/pos_order.py | 17 ++++------ addons/point_of_sale/models/pos_session.py | 3 +- addons/pos_hr/models/pos_order.py | 2 +- addons/pos_online_payment/models/pos_order.py | 2 +- addons/purchase/models/account_invoice.py | 6 ++-- addons/purchase/models/purchase.py | 20 ++++-------- .../models/purchase_requisition.py | 4 +-- addons/purchase_stock/models/purchase.py | 4 +-- addons/repair/models/repair.py | 10 +++--- addons/sale/models/sale_order.py | 24 +++----------- addons/sale/models/utm_campaign.py | 2 +- addons/sale_expense/models/hr_expense.py | 1 - addons/sale_management/models/sale_order.py | 4 --- addons/sale_project/models/sale_order.py | 3 +- addons/sale_stock/models/sale_order.py | 4 +-- addons/stock/models/stock_move.py | 10 +++--- addons/stock/models/stock_picking.py | 16 +++------- addons/stock/models/stock_scrap.py | 25 +++++++-------- .../models/stock_landed_cost.py | 15 ++++----- .../models/stock_picking.py | 1 - .../models/stock_picking_batch.py | 11 +++---- .../models/test_base_import.py | 10 ++---- .../security/ir.model.access.csv | 1 - .../tests/test_base_import.py | 4 --- .../test_new_api/models/test_new_api.py | 4 +-- .../test_new_api/tests/test_new_fields.py | 4 +-- odoo/fields.py | 8 ++--- odoo/models.py | 13 -------- 50 files changed, 152 insertions(+), 290 deletions(-) diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py index 6968bb4ba18..f895ca159c1 100644 --- a/addons/account/models/account_move.py +++ b/addons/account/models/account_move.py @@ -100,7 +100,6 @@ class AccountMove(models.Model): string='Date', index=True, compute='_compute_date', store=True, required=True, readonly=False, precompute=True, - states={'posted': [('readonly', True)], 'cancel': [('readonly', True)]}, copy=False, tracking=True, ) @@ -144,7 +143,6 @@ class AccountMove(models.Model): string='Journal', compute='_compute_journal_id', inverse='_inverse_journal_id', store=True, readonly=False, precompute=True, required=True, - states={'draft': [('readonly', False)]}, check_company=True, domain="[('id', 'in', suitable_journal_ids)]", ) @@ -159,8 +157,6 @@ class AccountMove(models.Model): 'move_id', string='Journal Items', copy=True, - readonly=True, - states={'draft': [('readonly', False)]}, ) # === Payment fields === # @@ -266,40 +262,32 @@ class AccountMove(models.Model): 'move_id', string='Invoice lines', copy=False, - readonly=True, domain=[('display_type', 'in', ('product', 'line_section', 'line_note'))], - states={'draft': [('readonly', False)]}, ) # === Date fields === # invoice_date = fields.Date( string='Invoice/Bill Date', - readonly=True, - states={'draft': [('readonly', False)]}, index=True, copy=False, ) invoice_date_due = fields.Date( string='Due Date', compute='_compute_invoice_date_due', store=True, readonly=False, - states={'draft': [('readonly', False)]}, index=True, copy=False, ) delivery_date = fields.Date( string='Delivery Date', copy=False, - readonly=True, store=True, compute='_compute_delivery_date', - states={'draft': [('readonly', False)]}, ) show_delivery_date = fields.Boolean(compute='_compute_show_delivery_date') invoice_payment_term_id = fields.Many2one( comodel_name='account.payment.term', string='Payment Terms', compute='_compute_invoice_payment_term_id', store=True, readonly=False, precompute=True, - states={'posted': [('readonly', True)], 'cancel': [('readonly', True)]}, check_company=True, ) needed_terms = fields.Binary(compute='_compute_needed_terms') @@ -311,9 +299,8 @@ class AccountMove(models.Model): partner_id = fields.Many2one( 'res.partner', string='Partner', - readonly=True, + readonly=False, tracking=True, - states={'draft': [('readonly', False)]}, inverse='_inverse_partner_id', check_company=True, change_default=True, @@ -348,7 +335,6 @@ class AccountMove(models.Model): string='Fiscal Position', check_company=True, compute='_compute_fiscal_position_id', store=True, readonly=False, precompute=True, - states={'posted': [('readonly', True)], 'cancel': [('readonly', True)]}, ondelete="restrict", help="Fiscal positions are used to adapt taxes and accounts for particular " "customers or sales orders/invoices. The default value comes from the customer.", @@ -402,7 +388,6 @@ class AccountMove(models.Model): tracking=True, required=True, compute='_compute_currency_id', inverse='_inverse_currency_id', store=True, readonly=False, precompute=True, - states={'posted': [('readonly', True)], 'cancel': [('readonly', True)]}, ) # === Amount fields === # @@ -551,8 +536,6 @@ class AccountMove(models.Model): invoice_cash_rounding_id = fields.Many2one( comodel_name='account.cash.rounding', string='Cash Rounding Method', - readonly=True, - states={'draft': [('readonly', False)]}, help='Defines the smallest coinage of the currency that can be used to pay by cash.', ) invoice_pdf_report_id = fields.Many2one( diff --git a/addons/event/models/event_registration.py b/addons/event/models/event_registration.py index 44261ae5b86..760116d24c7 100644 --- a/addons/event/models/event_registration.py +++ b/addons/event/models/event_registration.py @@ -16,11 +16,9 @@ class EventRegistration(models.Model): # event event_id = fields.Many2one( - 'event.event', string='Event', required=True, - readonly=True, states={'draft': [('readonly', False)]}) + 'event.event', string='Event', required=True) event_ticket_id = fields.Many2one( - 'event.event.ticket', string='Event Ticket', readonly=True, ondelete='restrict', - states={'draft': [('readonly', False)]}) + 'event.event.ticket', string='Event Ticket', ondelete='restrict') active = fields.Boolean(default=True) # utm informations utm_campaign_id = fields.Many2one('utm.campaign', 'Campaign', index=True, ondelete='set null') @@ -46,7 +44,7 @@ class EventRegistration(models.Model): event_user_id = fields.Many2one(string='Event Responsible', related='event_id.user_id', readonly=True) company_id = fields.Many2one( 'res.company', string='Company', related='event_id.company_id', - store=True, readonly=True, states={'draft': [('readonly', False)]}) + store=True, readonly=False) state = fields.Selection([ ('draft', 'Unconfirmed'), ('cancel', 'Cancelled'), ('open', 'Confirmed'), ('done', 'Attended')], diff --git a/addons/event_booth_sale/models/event_booth.py b/addons/event_booth_sale/models/event_booth.py index 1e00e4a6d09..ecf1ea26f48 100644 --- a/addons/event_booth_sale/models/event_booth.py +++ b/addons/event_booth_sale/models/event_booth.py @@ -17,7 +17,7 @@ class EventBooth(models.Model): groups='sales_team.group_sale_salesman', copy=False) sale_order_line_id = fields.Many2one( 'sale.order.line', string='Final Sale Order Line', ondelete='set null', - readonly=True, states={'available': [('readonly', False)]}, + readonly=False, groups='sales_team.group_sale_salesman', copy=False) sale_order_id = fields.Many2one( related='sale_order_line_id.order_id', store='True', readonly=True, diff --git a/addons/hr_expense/models/hr_expense.py b/addons/hr_expense/models/hr_expense.py index 6d27704a239..6b835b19eee 100644 --- a/addons/hr_expense/models/hr_expense.py +++ b/addons/hr_expense/models/hr_expense.py @@ -46,20 +46,17 @@ class HrExpense(models.Model): res = [('id', '=', employee.id), '|', ('company_id', '=', False), ('company_id', '=', employee.company_id.id)] return res - name = fields.Char('Description', compute='_compute_name', readonly=False, store=True, precompute=True, required=True, copy=True, - states={'done': [('readonly', True)]}) - date = fields.Date(states={'done': [('readonly', True)]}, default=fields.Date.context_today, string="Expense Date") + name = fields.Char('Description', compute='_compute_name', readonly=False, store=True, precompute=True, required=True, copy=True) + date = fields.Date(default=fields.Date.context_today, string="Expense Date") accounting_date = fields.Date(string="Accounting Date", related='sheet_id.accounting_date', store=True, groups='account.group_account_invoice,account.group_account_readonly') employee_id = fields.Many2one('hr.employee', compute='_compute_employee_id', string="Employee", store=True, required=True, readonly=False, tracking=True, - states={'approved': [('readonly', True)], 'done': [('readonly', True)]}, default=_default_employee_id, domain=lambda self: self._get_employee_id_domain(), check_company=True) # product_id not required to allow create an expense without product via mail alias, but should be required on the view. product_id = fields.Many2one( 'product.product', string='Category', tracking=True, - states={'done': [('readonly', True)]}, check_company=True, domain="[('can_be_expensed', '=', True)]", ondelete='restrict', @@ -70,9 +67,9 @@ class HrExpense(models.Model): domain="[('category_id', '=', product_uom_category_id)]") product_uom_category_id = fields.Many2one(related='product_id.uom_id.category_id', readonly=True, string="UoM Category") unit_amount = fields.Float("Unit Price", compute='_compute_unit_amount', readonly=False, store=True, precompute=True, required=True, copy=True, - states={'done': [('readonly', True)]}, digits='Product Price') + digits='Product Price') unit_amount_display = fields.Float("Unit Price Display", compute='_compute_unit_amount_display') - quantity = fields.Float(required=True, states={'done': [('readonly', True)]}, digits='Product Unit of Measure', default=1) + quantity = fields.Float(required=True, digits='Product Unit of Measure', default=1) tax_ids = fields.Many2many('account.tax', 'expense_tax', 'expense_id', 'tax_id', compute='_compute_tax_ids', store=True, readonly=False, precompute=True, check_company=True, @@ -85,8 +82,9 @@ class HrExpense(models.Model): company_currency_id = fields.Many2one('res.currency', string="Report Company Currency", related='company_id.currency_id', readonly=True) total_amount_company = fields.Monetary('Total', tracking=True, compute='_compute_total_amount_company', inverse='_inverse_total_amount_company', store=True, currency_field='company_currency_id', readonly=False) - company_id = fields.Many2one('res.company', string='Company', required=True, readonly=True, states={'draft': [('readonly', False)], 'refused': [('readonly', False)]}, default=lambda self: self.env.company) - currency_id = fields.Many2one('res.currency', string='Currency', required=True, readonly=False, store=True, states={'reported': [('readonly', True)], 'approved': [('readonly', True)], 'done': [('readonly', True)]}, compute='_compute_currency_id', default=lambda self: self.env.company.currency_id) + company_id = fields.Many2one('res.company', string='Company', required=True, default=lambda self: self.env.company) + currency_id = fields.Many2one('res.currency', string='Currency', required=True, store=True, readonly=False, + compute='_compute_currency_id', default=lambda self: self.env.company.currency_id) currency_rate = fields.Float(compute='_compute_currency_rate', tracking=True) account_id = fields.Many2one( 'account.account', @@ -96,11 +94,11 @@ class HrExpense(models.Model): domain="[('account_type', 'not in', ('asset_receivable','liability_payable','asset_cash','liability_credit_card'))]", help="An expense account is expected", ) - description = fields.Text('Internal Notes', readonly=True, states={'draft': [('readonly', False)], 'reported': [('readonly', False)], 'refused': [('readonly', False)]}) + description = fields.Text('Internal Notes') payment_mode = fields.Selection([ ("own_account", "Employee (to reimburse)"), ("company_account", "Company") - ], default='own_account', tracking=True, states={'done': [('readonly', True)], 'approved': [('readonly', True)], 'reported': [('readonly', True)]}, string="Paid By") + ], default='own_account', tracking=True, string="Paid By") attachment_number = fields.Integer('Number of Attachments', compute='_compute_attachment_number') state = fields.Selection( selection=[ @@ -1000,12 +998,12 @@ class HrExpenseSheet(models.Model): ], copy=False) approval_date = fields.Datetime('Approval Date', readonly=True) - company_id = fields.Many2one('res.company', string='Company', required=True, readonly=True, states={'draft': [('readonly', False)]}, default=lambda self: self.env.company) + company_id = fields.Many2one('res.company', string='Company', required=True, default=lambda self: self.env.company) company_currency_id = fields.Many2one(comodel_name='res.currency', string="Report Company Currency", related='company_id.currency_id') - 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()) + employee_id = fields.Many2one('hr.employee', string="Employee", required=True, tracking=True, 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) - department_id = fields.Many2one('hr.department', compute='_compute_from_employee_id', store=True, readonly=False, copy=False, string='Department', states={'post': [('readonly', True)], 'done': [('readonly', 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)]) + department_id = fields.Many2one('hr.department', compute='_compute_from_employee_id', store=True, readonly=False, copy=False, string='Department') + user_id = fields.Many2one('res.users', 'Manager', compute='_compute_from_employee_id', store=True, readonly=False, copy=False, tracking=True, domain=lambda self: [('groups_id', 'in', self.env.ref('hr_expense.group_hr_expense_team_approver').id)]) # === Amount fields === # total_amount = fields.Monetary('Total', currency_field='company_currency_id', compute='_compute_amount', store=True, tracking=True) @@ -1014,8 +1012,7 @@ class HrExpenseSheet(models.Model): amount_residual = fields.Monetary(string="Amount Due", currency_field='company_currency_id', compute='_compute_from_account_move_ids', store=True) - currency_id = fields.Many2one('res.currency', string='Currency', states={'draft': [('readonly', False)]}, - compute='_compute_currency_id', store=True, readonly=True) + currency_id = fields.Many2one('res.currency', string='Currency', compute='_compute_currency_id', store=True, readonly=False) is_multiple_currency = fields.Boolean("Handle lines with different currencies", compute='_compute_is_multiple_currency') # === Account fields === # @@ -1032,7 +1029,6 @@ class HrExpenseSheet(models.Model): employee_journal_id = fields.Many2one( 'account.journal', string='Journal', - states={'done': [('readonly', True)], 'post': [('readonly', True)]}, check_company=True, domain="[('type', '=', 'purchase')]", default=_default_journal_id, diff --git a/addons/hr_holidays/models/hr_leave.py b/addons/hr_holidays/models/hr_leave.py index 339fe5000c6..da166f15ce7 100644 --- a/addons/hr_holidays/models/hr_leave.py +++ b/addons/hr_holidays/models/hr_leave.py @@ -153,7 +153,6 @@ class HolidaysRequest(models.Model): # leave type configuration holiday_status_id = fields.Many2one( "hr.leave.type", compute='_compute_from_employee_id', store=True, string="Time Off Type", required=True, readonly=False, - states={'cancel': [('readonly', True)], 'refuse': [('readonly', True)], 'validate1': [('readonly', True)], 'validate': [('readonly', True)]}, domain="[('company_id', '?=', employee_company_id), '|', ('requires_allocation', '=', 'no'), ('has_valid_allocation', '=', True)]", tracking=True) holiday_allocation_id = fields.Many2one( 'hr.leave.allocation', compute='_compute_from_holiday_status_id', string="Allocation", store=True, readonly=False) @@ -163,23 +162,19 @@ class HolidaysRequest(models.Model): employee_id = fields.Many2one( 'hr.employee', compute='_compute_from_employee_ids', store=True, string='Employee', index=True, readonly=False, ondelete="restrict", - states={'cancel': [('readonly', True)], 'refuse': [('readonly', True)], 'validate1': [('readonly', True)], 'validate': [('readonly', True)]}, tracking=True, compute_sudo=False) employee_company_id = fields.Many2one(related='employee_id.company_id', readonly=True, store=True) active_employee = fields.Boolean(related='employee_id.active', string='Employee Active', readonly=True) tz_mismatch = fields.Boolean(compute='_compute_tz_mismatch') tz = fields.Selection(_tz_get, compute='_compute_tz') department_id = fields.Many2one( - 'hr.department', compute='_compute_department_id', store=True, string='Department', readonly=False, - states={'cancel': [('readonly', True)], 'refuse': [('readonly', True)], 'validate1': [('readonly', True)], 'validate': [('readonly', True)]}) - notes = fields.Text('Reasons', readonly=True, states={'draft': [('readonly', False)], 'confirm': [('readonly', False)]}) + 'hr.department', compute='_compute_department_id', store=True, string='Department', readonly=False) + notes = fields.Text('Reasons', readonly=False) # duration date_from = fields.Datetime( - 'Start Date', compute='_compute_date_from_to', store=True, readonly=False, index=True, copy=False, required=True, tracking=True, - states={'cancel': [('readonly', True)], 'refuse': [('readonly', True)], 'validate1': [('readonly', True)], 'validate': [('readonly', True)]}) + 'Start Date', compute='_compute_date_from_to', store=True, readonly=False, index=True, copy=False, required=True, tracking=True) date_to = fields.Datetime( - 'End Date', compute='_compute_date_from_to', store=True, readonly=False, copy=False, required=True, tracking=True, - states={'cancel': [('readonly', True)], 'refuse': [('readonly', True)], 'validate1': [('readonly', True)], 'validate': [('readonly', True)]}) + 'End Date', compute='_compute_date_from_to', store=True, readonly=False, copy=False, required=True, tracking=True) number_of_days = fields.Float( 'Duration (Days)', compute='_compute_number_of_days', store=True, readonly=False, copy=False, tracking=True, help='Number of days of the time off request. Used in the calculation. To manually correct the duration, use this field.') @@ -201,21 +196,19 @@ class HolidaysRequest(models.Model): ('company', 'By Company'), ('department', 'By Department'), ('category', 'By Employee Tag')], - string='Allocation Mode', readonly=True, required=True, default='employee', - states={'draft': [('readonly', False)], 'confirm': [('readonly', False)]}, + string='Allocation Mode', readonly=False, required=True, default='employee', help='By Employee: Allocation/Request for individual Employee, By Employee Tag: Allocation/Request for group of employees in category') employee_ids = fields.Many2many( - 'hr.employee', compute='_compute_from_holiday_type', store=True, string='Employees', readonly=False, groups="hr_holidays.group_hr_holidays_user", - states={'cancel': [('readonly', True)], 'refuse': [('readonly', True)], 'validate1': [('readonly', True)], 'validate': [('readonly', True)]}) + 'hr.employee', compute='_compute_from_holiday_type', store=True, string='Employees', readonly=False, groups="hr_holidays.group_hr_holidays_user") multi_employee = fields.Boolean( compute='_compute_from_employee_ids', store=True, compute_sudo=False, help='Holds whether this allocation concerns more than 1 employee') category_id = fields.Many2one( 'hr.employee.category', compute='_compute_from_holiday_type', store=True, string='Employee Tag', - states={'draft': [('readonly', False)], 'confirm': [('readonly', False)]}, help='Category of Employee') + readonly=False, help='Category of Employee') mode_company_id = fields.Many2one( 'res.company', compute='_compute_from_holiday_type', store=True, string='Company Mode', - states={'draft': [('readonly', False)], 'confirm': [('readonly', False)]}) + readonly=False) first_approver_id = fields.Many2one( 'hr.employee', string='First Approval', readonly=True, copy=False, help='This area is automatically filled by the user who validate the time off') diff --git a/addons/hr_holidays/models/hr_leave_allocation.py b/addons/hr_holidays/models/hr_leave_allocation.py index 2a75c88164b..25aad9dc6a7 100644 --- a/addons/hr_holidays/models/hr_leave_allocation.py +++ b/addons/hr_holidays/models/hr_leave_allocation.py @@ -57,28 +57,25 @@ class HolidaysAllocation(models.Model): "\nThe status is 'Refused', when an allocation request is refused by manager." + "\nThe status is 'Approved', when an allocation request is approved by manager.") date_from = fields.Date('Start Date', index=True, copy=False, default=fields.Date.context_today, - states={'draft': [('readonly', False)], 'confirm': [('readonly', False)]}, tracking=True, required=True) - date_to = fields.Date('End Date', copy=False, tracking=True, - states={'cancel': [('readonly', True)], 'refuse': [('readonly', True)], 'validate1': [('readonly', True)], 'validate': [('readonly', True)]}) + tracking=True, required=True) + date_to = fields.Date('End Date', copy=False, tracking=True) holiday_status_id = fields.Many2one( "hr.leave.type", compute='_compute_holiday_status_id', store=True, string="Time Off Type", required=True, readonly=False, - states={'cancel': [('readonly', True)], 'refuse': [('readonly', True)], 'validate1': [('readonly', True)], 'validate': [('readonly', True)]}, domain=_domain_holiday_status_id, default=_default_holiday_status_id) employee_id = fields.Many2one( - 'hr.employee', compute='_compute_from_employee_ids', store=True, string='Employee', index=True, readonly=False, ondelete="restrict", tracking=True, - states={'cancel': [('readonly', True)], 'refuse': [('readonly', True)], 'validate': [('readonly', True)]}) + 'hr.employee', compute='_compute_from_employee_ids', store=True, string='Employee', index=True, readonly=False, ondelete="restrict", tracking=True) employee_company_id = fields.Many2one(related='employee_id.company_id', readonly=True, store=True) active_employee = fields.Boolean('Active Employee', related='employee_id.active', readonly=True) manager_id = fields.Many2one('hr.employee', compute='_compute_manager_id', store=True, string='Manager') - notes = fields.Text('Reasons', readonly=True, states={'draft': [('readonly', False)], 'confirm': [('readonly', False)]}) + notes = fields.Text('Reasons', readonly=False) # duration number_of_days = fields.Float( 'Number of Days', compute='_compute_from_holiday_status_id', store=True, readonly=False, tracking=True, default=1, help='Duration in days. Reference field to use when necessary.') number_of_days_display = fields.Float( 'Duration (days)', compute='_compute_number_of_days_display', - states={'draft': [('readonly', False)], 'confirm': [('readonly', False)]}, + readonly=False, help="If Accrual Allocation: Number of days allocated in addition to the ones you will get via the accrual' system.") number_of_hours_display = fields.Float( 'Duration (hours)', compute='_compute_number_of_hours_display', @@ -101,27 +98,23 @@ class HolidaysAllocation(models.Model): ('company', 'By Company'), ('department', 'By Department'), ('category', 'By Employee Tag')], - string='Allocation Mode', readonly=True, required=True, default='employee', - states={'draft': [('readonly', False)], 'confirm': [('readonly', False)]}, + string='Allocation Mode', readonly=False, required=True, default='employee', help="Allow to create requests in batchs:\n- By Employee: for a specific employee" "\n- By Company: all employees of the specified company" "\n- By Department: all employees of the specified department" "\n- By Employee Tag: all employees of the specific employee group category") employee_ids = fields.Many2many( - 'hr.employee', compute='_compute_from_holiday_type', store=True, string='Employees', readonly=False, - states={'cancel': [('readonly', True)], 'refuse': [('readonly', True)], 'validate': [('readonly', True)]}) + 'hr.employee', compute='_compute_from_holiday_type', store=True, string='Employees', readonly=False) multi_employee = fields.Boolean( compute='_compute_from_employee_ids', store=True, help='Holds whether this allocation concerns more than 1 employee') mode_company_id = fields.Many2one( - 'res.company', compute='_compute_from_holiday_type', store=True, string='Company Mode', readonly=False, - states={'cancel': [('readonly', True)], 'refuse': [('readonly', True)], 'validate': [('readonly', True)]}) + 'res.company', compute='_compute_from_holiday_type', store=True, string='Company Mode', readonly=False) department_id = fields.Many2one( 'hr.department', compute='_compute_department_id', store=True, string='Department', - states={'draft': [('readonly', False)], 'confirm': [('readonly', False)]}) + readonly=False) category_id = fields.Many2one( - 'hr.employee.category', compute='_compute_from_holiday_type', store=True, string='Employee Tag', readonly=False, - states={'cancel': [('readonly', True)], 'refuse': [('readonly', True)], 'validate': [('readonly', True)]}) + 'hr.employee.category', compute='_compute_from_holiday_type', store=True, string='Employee Tag', readonly=False) # accrual configuration lastcall = fields.Date("Date of the last accrual allocation", readonly=True, default=fields.Date.context_today) nextcall = fields.Date("Date of the next accrual allocation", default=False, readonly=True) @@ -129,8 +122,7 @@ class HolidaysAllocation(models.Model): [ ('regular', 'Regular Allocation'), ('accrual', 'Accrual Allocation') - ], string="Allocation Type", default="regular", required=True, readonly=True, - states={'draft': [('readonly', False)], 'confirm': [('readonly', False)]}) + ], string="Allocation Type", default="regular", required=True, readonly=False) is_officer = fields.Boolean(compute='_compute_is_officer') accrual_plan_id = fields.Many2one('hr.leave.accrual.plan', compute="_compute_from_holiday_status_id", store=True, readonly=False, domain="['|', ('time_off_type_id', '=', False), ('time_off_type_id', '=', holiday_status_id)]", tracking=True) max_leaves = fields.Float(compute='_compute_leaves') diff --git a/addons/l10n_ar/models/account_move.py b/addons/l10n_ar/models/account_move.py index ab5fbb0afc5..c56a6c70976 100644 --- a/addons/l10n_ar/models/account_move.py +++ b/addons/l10n_ar/models/account_move.py @@ -32,8 +32,8 @@ class AccountMove(models.Model): compute='_compute_l10n_ar_afip_concept', selection='_get_afip_invoice_concepts', string="AFIP Concept", help="A concept is suggested regarding the type of the products on the invoice but it is allowed to force a" " different type if required.") - l10n_ar_afip_service_start = fields.Date(string='AFIP Service Start Date', readonly=True, states={'draft': [('readonly', False)]}) - l10n_ar_afip_service_end = fields.Date(string='AFIP Service End Date', readonly=True, states={'draft': [('readonly', False)]}) + l10n_ar_afip_service_start = fields.Date(string='AFIP Service Start Date') + l10n_ar_afip_service_end = fields.Date(string='AFIP Service End Date') def _is_manual_document_number(self): """ Document number should be manual input by user when the journal use documents and diff --git a/addons/l10n_id_efaktur/models/account_move.py b/addons/l10n_id_efaktur/models/account_move.py index 6844e3b412b..6d66a359b9f 100644 --- a/addons/l10n_id_efaktur/models/account_move.py +++ b/addons/l10n_id_efaktur/models/account_move.py @@ -36,7 +36,7 @@ class AccountMove(models.Model): ('08', '08 Penyerahan yang PPN-nya Dibebaskan (Impor Barang Tertentu)'), ('09', '09 Penyerahan Aktiva ( Pasal 16D UU PPN )'), ], string='Kode Transaksi', help='Dua digit pertama nomor pajak', - readonly=False, states={'posted': [('readonly', True)], 'cancel': [('readonly', True)]}, copy=False, + readonly=False, copy=False, compute="_compute_kode_transaksi", store=True) l10n_id_need_kode_transaksi = fields.Boolean(compute='_compute_need_kode_transaksi') diff --git a/addons/l10n_in/models/account_invoice.py b/addons/l10n_in/models/account_invoice.py index a7b30a97541..8aec7e1bf5c 100644 --- a/addons/l10n_in/models/account_invoice.py +++ b/addons/l10n_in/models/account_invoice.py @@ -26,10 +26,10 @@ class AccountMove(models.Model): l10n_in_state_id = fields.Many2one('res.country.state', string="Place of supply", compute="_compute_l10n_in_state_id", store=True, readonly=False) l10n_in_gstin = fields.Char(string="GSTIN") # For Export invoice this data is need in GSTR report - l10n_in_shipping_bill_number = fields.Char('Shipping bill number', readonly=True, states={'draft': [('readonly', False)]}) - l10n_in_shipping_bill_date = fields.Date('Shipping bill date', readonly=True, states={'draft': [('readonly', False)]}) - l10n_in_shipping_port_code_id = fields.Many2one('l10n_in.port.code', 'Port code', readonly=True, states={'draft': [('readonly', False)]}) - l10n_in_reseller_partner_id = fields.Many2one('res.partner', 'Reseller', domain=[('vat', '!=', False)], help="Only Registered Reseller", readonly=True, states={'draft': [('readonly', False)]}) + l10n_in_shipping_bill_number = fields.Char('Shipping bill number') + l10n_in_shipping_bill_date = fields.Date('Shipping bill date') + l10n_in_shipping_port_code_id = fields.Many2one('l10n_in.port.code', 'Port code') + l10n_in_reseller_partner_id = fields.Many2one('res.partner', 'Reseller', domain=[('vat', '!=', False)], help="Only Registered Reseller") l10n_in_journal_type = fields.Selection(string="Journal Type", related='journal_id.type') @api.depends('amount_total') diff --git a/addons/l10n_in_purchase/models/purchase_order.py b/addons/l10n_in_purchase/models/purchase_order.py index 5e131817732..f1cb38979ba 100644 --- a/addons/l10n_in_purchase/models/purchase_order.py +++ b/addons/l10n_in_purchase/models/purchase_order.py @@ -17,7 +17,7 @@ class PurchaseOrder(models.Model): ('special_economic_zone', 'Special Economic Zone'), ('deemed_export', 'Deemed Export'), ('uin_holders', 'UIN Holders'), - ], string="GST Treatment", states=Purchase.READONLY_STATES, compute="_compute_l10n_in_gst_treatment", store=True) + ], string="GST Treatment", compute="_compute_l10n_in_gst_treatment", store=True) @api.depends('partner_id') def _compute_l10n_in_gst_treatment(self): diff --git a/addons/l10n_in_sale/models/sale_order.py b/addons/l10n_in_sale/models/sale_order.py index 02276e2b618..51cf937dc99 100644 --- a/addons/l10n_in_sale/models/sale_order.py +++ b/addons/l10n_in_sale/models/sale_order.py @@ -8,7 +8,7 @@ class SaleOrder(models.Model): _inherit = "sale.order" l10n_in_reseller_partner_id = fields.Many2one('res.partner', - string='Reseller', domain="[('vat', '!=', False), '|', ('company_id', '=', False), ('company_id', '=', company_id)]", readonly=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}) + string='Reseller', domain="[('vat', '!=', False), '|', ('company_id', '=', False), ('company_id', '=', company_id)]", readonly=False) l10n_in_gst_treatment = fields.Selection([ ('regular', 'Registered Business - Regular'), ('composition', 'Registered Business - Composition'), @@ -18,7 +18,7 @@ class SaleOrder(models.Model): ('special_economic_zone', 'Special Economic Zone'), ('deemed_export', 'Deemed Export'), ('uin_holders', 'UIN Holders'), - ], string="GST Treatment", readonly=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}, compute="_compute_l10n_in_gst_treatment", store=True) + ], string="GST Treatment", readonly=False, compute="_compute_l10n_in_gst_treatment", store=True) @api.depends('partner_id') def _compute_l10n_in_gst_treatment(self): diff --git a/addons/l10n_it_edi/models/account_invoice.py b/addons/l10n_it_edi/models/account_invoice.py index 2b7389f5a99..a027660f788 100644 --- a/addons/l10n_it_edi/models/account_invoice.py +++ b/addons/l10n_it_edi/models/account_invoice.py @@ -24,8 +24,8 @@ class AccountMove(models.Model): l10n_it_edi_transaction = fields.Char(copy=False, string="FatturaPA Transaction") l10n_it_edi_attachment_id = fields.Many2one('ir.attachment', copy=False, string="FatturaPA Attachment", ondelete="restrict") - l10n_it_stamp_duty = fields.Float(default=0, string="Dati Bollo", readonly=True, states={'draft': [('readonly', False)]}) - l10n_it_ddt_id = fields.Many2one('l10n_it.ddt', string='DDT', readonly=True, states={'draft': [('readonly', False)]}, copy=False) + l10n_it_stamp_duty = fields.Float(default=0, string="Dati Bollo") + l10n_it_ddt_id = fields.Many2one('l10n_it.ddt', string='DDT', copy=False) l10n_it_einvoice_name = fields.Char(compute='_compute_l10n_it_einvoice') l10n_it_einvoice_id = fields.Many2one('ir.attachment', string="Electronic invoice", compute='_compute_l10n_it_einvoice') diff --git a/addons/l10n_latam_check/models/account_payment.py b/addons/l10n_latam_check/models/account_payment.py index 0964502c42b..ddc37f3a4e5 100644 --- a/addons/l10n_latam_check/models/account_payment.py +++ b/addons/l10n_latam_check/models/account_payment.py @@ -13,7 +13,6 @@ class AccountPayment(models.Model): l10n_latam_check_id = fields.Many2one( comodel_name='account.payment', string='Check', - readonly=True, states={'draft': [('readonly', False)]}, copy=False, check_company=True, ) @@ -40,17 +39,15 @@ class AccountPayment(models.Model): comodel_name='res.bank', string='Check Bank', compute='_compute_l10n_latam_check_bank_id', store=True, readonly=False, - states={'posted': [('readonly', True)], 'cancel': [('readonly', True)]}, ) l10n_latam_check_issuer_vat = fields.Char( string='Check Issuer VAT', compute='_compute_l10n_latam_check_issuer_vat', store=True, readonly=False, - states={'posted': [('readonly', True)], 'cancel': [('readonly', True)]}, ) l10n_latam_check_payment_date = fields.Date( string='Check Cash-In Date', help="Date from when you can cash in the check, turn the check into cash", - readonly=True, states={'draft': [('readonly', False)]}, + readonly=False, ) # This is a technical field for the view only diff --git a/addons/l10n_latam_invoice_document/models/account_move.py b/addons/l10n_latam_invoice_document/models/account_move.py index 99a7ed74144..d76fab5416e 100644 --- a/addons/l10n_latam_invoice_document/models/account_move.py +++ b/addons/l10n_latam_invoice_document/models/account_move.py @@ -64,11 +64,10 @@ class AccountMove(models.Model): l10n_latam_available_document_type_ids = fields.Many2many('l10n_latam.document.type', compute='_compute_l10n_latam_available_document_types') l10n_latam_document_type_id = fields.Many2one( - 'l10n_latam.document.type', string='Document Type', readonly=False, auto_join=True, index='btree_not_null', - states={'posted': [('readonly', True)]}, compute='_compute_l10n_latam_document_type', store=True) + 'l10n_latam.document.type', string='Document Type', readonly=False, auto_join=True, index='btree_not_null', compute='_compute_l10n_latam_document_type', store=True) l10n_latam_document_number = fields.Char( compute='_compute_l10n_latam_document_number', inverse='_inverse_l10n_latam_document_number', - string='Document Number', readonly=True, states={'draft': [('readonly', False)]}) + string='Document Number', readonly=False) l10n_latam_use_documents = fields.Boolean(related='journal_id.l10n_latam_use_documents') l10n_latam_manual_document_number = fields.Boolean(compute='_compute_l10n_latam_manual_document_number', string='Manual Number') l10n_latam_document_type_id_code = fields.Char(related='l10n_latam_document_type_id.code', string='Doc Type') diff --git a/addons/lunch/models/lunch_order.py b/addons/lunch/models/lunch_order.py index 8d40087ced0..9e9538f34f0 100644 --- a/addons/lunch/models/lunch_order.py +++ b/addons/lunch/models/lunch_order.py @@ -18,15 +18,13 @@ class LunchOrder(models.Model): product_id = fields.Many2one('lunch.product', string="Product", required=True) category_id = fields.Many2one( string='Product Category', related='product_id.category_id', store=True) - date = fields.Date('Order Date', required=True, readonly=True, - states={'new': [('readonly', False)]}, + date = fields.Date('Order Date', required=True, readonly=False, default=fields.Date.context_today) supplier_id = fields.Many2one( string='Vendor', related='product_id.supplier_id', store=True, index=True) available_today = fields.Boolean(related='supplier_id.available_today') order_deadline_passed = fields.Boolean(related='supplier_id.order_deadline_passed') - user_id = fields.Many2one('res.users', 'User', readonly=True, - states={'new': [('readonly', False)]}, + user_id = fields.Many2one('res.users', 'User', readonly=False, default=lambda self: self.env.uid) lunch_location_id = fields.Many2one('lunch.location', default=lambda self: self.env.user.last_lunch_location_id) note = fields.Text('Notes') diff --git a/addons/mail/models/fetchmail.py b/addons/mail/models/fetchmail.py index c3ba19c8ddd..7a3c9c6d333 100644 --- a/addons/mail/models/fetchmail.py +++ b/addons/mail/models/fetchmail.py @@ -40,8 +40,8 @@ class FetchmailServer(models.Model): ('draft', 'Not Confirmed'), ('done', 'Confirmed'), ], string='Status', index=True, readonly=True, copy=False, default='draft') - server = fields.Char(string='Server Name', readonly=True, help="Hostname or IP of the mail server", states={'draft': [('readonly', False)]}) - port = fields.Integer(readonly=True, states={'draft': [('readonly', False)]}) + server = fields.Char(string='Server Name', readonly=False, help="Hostname or IP of the mail server") + port = fields.Integer() server_type = fields.Selection([ ('imap', 'IMAP Server'), ('pop', 'POP Server'), @@ -54,13 +54,13 @@ class FetchmailServer(models.Model): original = fields.Boolean('Keep Original', help="Whether a full original copy of each email should be kept for reference " "and attached to each processed message. This will usually double the size of your message database.") date = fields.Datetime(string='Last Fetch Date', readonly=True) - user = fields.Char(string='Username', readonly=True, states={'draft': [('readonly', False)]}) - password = fields.Char(readonly=True, states={'draft': [('readonly', False)]}) + user = fields.Char(string='Username', readonly=False) + password = fields.Char() object_id = fields.Many2one('ir.model', string="Create a New Record", help="Process each incoming mail as part of a conversation " "corresponding to this document type. This will create " "new documents for new conversations, or attach follow-up " "emails to the existing conversations (documents).") - priority = fields.Integer(string='Server Priority', readonly=True, states={'draft': [('readonly', False)]}, help="Defines the order of processing, lower values mean higher priority", default=5) + priority = fields.Integer(string='Server Priority', readonly=False, help="Defines the order of processing, lower values mean higher priority", default=5) message_ids = fields.One2many('mail.mail', 'fetchmail_server_id', string='Messages', readonly=True) configuration = fields.Text('Configuration', readonly=True) script = fields.Char(readonly=True, default='/mail/static/scripts/odoo-mailgate.py') diff --git a/addons/mass_mailing/models/mailing.py b/addons/mass_mailing/models/mailing.py index f8fe8b266a0..635d4a40158 100644 --- a/addons/mass_mailing/models/mailing.py +++ b/addons/mass_mailing/models/mailing.py @@ -99,13 +99,11 @@ class MassMailing(models.Model): schedule_type = fields.Selection( [('now', 'Send now'), ('scheduled', 'Send on')], string='Schedule', default='now', - readonly=True, required=True, - states={'draft': [('readonly', False)], 'in_queue': [('readonly', False)]}) + readonly=False, required=True) schedule_date = fields.Datetime( string='Scheduled for', - compute='_compute_schedule_date', readonly=True, store=True, - copy=True, tracking=True, - states={'draft': [('readonly', False)], 'in_queue': [('readonly', False)]}) + compute='_compute_schedule_date', readonly=False, store=True, + copy=True, tracking=True) calendar_date = fields.Datetime( 'Calendar Date', compute='_compute_calendar_date', store=True, diff --git a/addons/mrp/models/mrp_production.py b/addons/mrp/models/mrp_production.py index 7859d37cb71..ac558c8744b 100644 --- a/addons/mrp/models/mrp_production.py +++ b/addons/mrp/models/mrp_production.py @@ -55,15 +55,13 @@ class MrpProduction(models.Model): backorder_sequence = fields.Integer("Backorder Sequence", default=0, copy=False, help="Backorder sequence, if equals to 0 means there is not related backorder") origin = fields.Char( 'Source', copy=False, - states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}, help="Reference of the document that generated this production order request.") product_id = fields.Many2one( 'product.product', 'Product', domain="[('type', 'in', ['product', 'consu'])]", compute='_compute_product_id', store=True, copy=True, precompute=True, - readonly=True, required=True, check_company=True, - states={'draft': [('readonly', False)]}) + readonly=False, required=True, check_company=True) product_variant_attributes = fields.Many2many('product.template.attribute.value', related='product_id.product_template_attribute_value_ids') workcenter_id = fields.Many2one('mrp.workcenter', store=False) # Only used for search in view_mrp_production_filter product_tracking = fields.Selection(related='product_id.tracking') @@ -163,7 +161,7 @@ class MrpProduction(models.Model): move_raw_ids = fields.One2many( 'stock.move', 'raw_material_production_id', 'Components', compute='_compute_move_raw_ids', store=True, readonly=False, - copy=False, states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}, + copy=False, domain=[('scrapped', '=', False)]) move_finished_ids = fields.One2many( 'stock.move', 'production_id', 'Finished Products', readonly=False, @@ -187,7 +185,6 @@ class MrpProduction(models.Model): help='Technical field to check when we can reserve quantities') user_id = fields.Many2one( 'res.users', 'Responsible', default=lambda self: self.env.user, - states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}, domain=lambda self: [('groups_id', 'in', self.env.ref('mrp.group_mrp_user').id)]) company_id = fields.Many2one( 'res.company', 'Company', default=lambda self: self.env.company, diff --git a/addons/mrp/models/mrp_unbuild.py b/addons/mrp/models/mrp_unbuild.py index b5bfa888da6..f6d4c321c06 100644 --- a/addons/mrp/models/mrp_unbuild.py +++ b/addons/mrp/models/mrp_unbuild.py @@ -19,18 +19,18 @@ class MrpUnbuild(models.Model): product_id = fields.Many2one( 'product.product', 'Product', check_company=True, domain="[('type', 'in', ['product', 'consu'])]", - required=True, states={'done': [('readonly', True)]}) + required=True) company_id = fields.Many2one( 'res.company', 'Company', default=lambda s: s.env.company, - required=True, index=True, states={'done': [('readonly', True)]}) + required=True, index=True) product_qty = fields.Float( 'Quantity', default=1.0, - required=True, states={'done': [('readonly', True)]}) + required=True) product_uom_id = fields.Many2one( 'uom.uom', 'Unit of Measure', compute='_compute_product_uom_id', store=True, readonly=False, precompute=True, - required=True, states={'done': [('readonly', True)]}) + required=True) bom_id = fields.Many2one( 'mrp.bom', 'Bill of Material', domain="""[ @@ -43,13 +43,12 @@ class MrpUnbuild(models.Model): '|', ('company_id', '=', company_id), ('company_id', '=', False) - ] -""", - states={'done': [('readonly', True)]}, check_company=True) + ]""", + check_company=True) mo_id = fields.Many2one( 'mrp.production', 'Manufacturing Order', domain="[('state', '=', 'done'), ('product_id', '=?', product_id), ('bom_id', '=?', bom_id)]", - states={'done': [('readonly', True)]}, check_company=True) + check_company=True) mo_bom_id = fields.Many2one('mrp.bom', 'Bill of Material used on the Production Order', related='mo_id.bom_id') lot_id = fields.Many2one( 'stock.lot', 'Lot/Serial Number', @@ -60,13 +59,13 @@ class MrpUnbuild(models.Model): domain="[('usage','=','internal')]", check_company=True, compute='_compute_location_id', store=True, readonly=False, precompute=True, - required=True, states={'done': [('readonly', True)]}, help="Location where the product you want to unbuild is.") + required=True, help="Location where the product you want to unbuild is.") location_dest_id = fields.Many2one( 'stock.location', 'Destination Location', domain="[('usage','=','internal')]", check_company=True, compute='_compute_location_id', store=True, readonly=False, precompute=True, - required=True, states={'done': [('readonly', True)]}, help="Location where you want to send the components resulting from the unbuild order.") + required=True, help="Location where you want to send the components resulting from the unbuild order.") consume_line_ids = fields.One2many( 'stock.move', 'consume_unbuild_id', readonly=True, string='Consumed Disassembly Lines') diff --git a/addons/mrp/models/mrp_workorder.py b/addons/mrp/models/mrp_workorder.py index 14832aaa567..05cc4dcecd5 100644 --- a/addons/mrp/models/mrp_workorder.py +++ b/addons/mrp/models/mrp_workorder.py @@ -22,12 +22,10 @@ class MrpWorkorder(models.Model): return workcenters.browse(workcenter_ids) name = fields.Char( - 'Work Order', required=True, - states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}) + 'Work Order', required=True) barcode = fields.Char(compute='_compute_barcode', store=True) workcenter_id = fields.Many2one( 'mrp.workcenter', 'Work Center', required=True, - states={'done': [('readonly', True)], 'cancel': [('readonly', True)], 'progress': [('readonly', True)]}, group_expand='_read_group_workcenter_id', check_company=True) working_state = fields.Selection( string='Workcenter Status', related='workcenter_id.working_state') # technical: used in views only @@ -73,17 +71,16 @@ class MrpWorkorder(models.Model): 'Start', compute='_compute_dates', inverse='_set_dates', - states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}, + readonly=False, store=True, copy=False) date_finished = fields.Datetime( 'End', compute='_compute_dates', inverse='_set_dates', - states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}, + readonly=False, store=True, copy=False) duration_expected = fields.Float( 'Expected Duration', digits=(16, 2), compute='_compute_duration_expected', - states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}, readonly=False, store=True) # in minutes duration = fields.Float( 'Real Duration', compute='_compute_duration', inverse='_set_duration', diff --git a/addons/mrp/models/stock_scrap.py b/addons/mrp/models/stock_scrap.py index b8f4184c8de..5484e9a2ca0 100644 --- a/addons/mrp/models/stock_scrap.py +++ b/addons/mrp/models/stock_scrap.py @@ -8,17 +8,16 @@ class StockScrap(models.Model): production_id = fields.Many2one( 'mrp.production', 'Manufacturing Order', - states={'done': [('readonly', True)]}, check_company=True) + check_company=True) workorder_id = fields.Many2one( 'mrp.workorder', 'Work Order', - states={'done': [('readonly', True)]}, check_company=True) # Not to restrict or prefer quants, but informative product_is_kit = fields.Boolean(related='product_id.is_kits') product_template = fields.Many2one(related='product_id.product_tmpl_id') bom_id = fields.Many2one( 'mrp.bom', 'Kit', domain="[('type', '=', 'phantom'), '|', ('product_id', '=', product_id), '&', ('product_id', '=', False), ('product_tmpl_id', '=', product_template)]", - states={'done': [('readonly', True)]}, check_company=True) + check_company=True) @api.onchange('workorder_id') def _onchange_workorder_id(self): diff --git a/addons/mrp_landed_costs/models/stock_landed_cost.py b/addons/mrp_landed_costs/models/stock_landed_cost.py index cb6d9c10304..edc6b5d40d8 100644 --- a/addons/mrp_landed_costs/models/stock_landed_cost.py +++ b/addons/mrp_landed_costs/models/stock_landed_cost.py @@ -12,7 +12,7 @@ class StockLandedCost(models.Model): ], ondelete={'manufacturing': 'set default'}) mrp_production_ids = fields.Many2many( 'mrp.production', string='Manufacturing order', - copy=False, states={'done': [('readonly', True)]}, groups='stock.group_stock_manager') + copy=False, groups='stock.group_stock_manager') @api.onchange('target_model') def _onchange_target_model(self): diff --git a/addons/point_of_sale/models/pos_order.py b/addons/point_of_sale/models/pos_order.py index 0399d09e901..c5fbd097c21 100644 --- a/addons/point_of_sale/models/pos_order.py +++ b/addons/point_of_sale/models/pos_order.py @@ -255,28 +255,24 @@ class PosOrder(models.Model): comodel_name='res.users', string='Responsible', help="Person who uses the cash register. It can be a reliever, a student or an interim employee.", default=lambda self: self.env.uid, - states={'done': [('readonly', True)], 'invoiced': [('readonly', True)]}, ) amount_tax = fields.Float(string='Taxes', digits=0, readonly=True, required=True) amount_total = fields.Float(string='Total', digits=0, readonly=True, required=True) - amount_paid = fields.Float(string='Paid', states={'draft': [('readonly', False)]}, - readonly=True, digits=0, required=True) + amount_paid = fields.Float(string='Paid', digits=0, required=True) amount_return = fields.Float(string='Returned', digits=0, required=True, readonly=True) margin = fields.Monetary(string="Margin", compute='_compute_margin') margin_percent = fields.Float(string="Margin (%)", compute='_compute_margin', digits=(12, 4)) is_total_cost_computed = fields.Boolean(compute='_compute_is_total_cost_computed', help="Allows to know if all the total cost of the order lines have already been computed") - lines = fields.One2many('pos.order.line', 'order_id', string='Order Lines', states={'draft': [('readonly', False)]}, readonly=True, copy=True) + lines = fields.One2many('pos.order.line', 'order_id', string='Order Lines', copy=True) company_id = fields.Many2one('res.company', string='Company', required=True, readonly=True) - pricelist_id = fields.Many2one('product.pricelist', string='Pricelist', states={ - 'draft': [('readonly', False)]}, readonly=True) - partner_id = fields.Many2one('res.partner', string='Customer', change_default=True, index='btree_not_null', states={'draft': [('readonly', False)], 'paid': [('readonly', False)]}) + pricelist_id = fields.Many2one('product.pricelist', string='Pricelist') + partner_id = fields.Many2one('res.partner', string='Customer', change_default=True, index='btree_not_null') sequence_number = fields.Integer(string='Sequence Number', help='A session-unique sequence number for the order', default=1) session_id = fields.Many2one( 'pos.session', string='Session', required=True, index=True, - domain="[('state', '=', 'opened')]", states={'draft': [('readonly', False)]}, - readonly=True) + domain="[('state', '=', 'opened')]") config_id = fields.Many2one('pos.config', related='session_id.config_id', string="Point of Sale", readonly=False) currency_id = fields.Many2one('res.currency', related='config_id.currency_id', string="Currency") currency_rate = fields.Float("Currency Rate", compute='_compute_currency_rate', compute_sudo=True, store=True, digits=0, readonly=True, @@ -299,8 +295,7 @@ class PosOrder(models.Model): sale_journal = fields.Many2one('account.journal', related='session_id.config_id.journal_id', string='Sales Journal', store=True, readonly=True, ondelete='restrict') fiscal_position_id = fields.Many2one( comodel_name='account.fiscal.position', string='Fiscal Position', - readonly=True, - states={'draft': [('readonly', False)]}, + readonly=False, ) payment_ids = fields.One2many('pos.payment', 'pos_order_id', string='Payments', readonly=True) session_move_id = fields.Many2one('account.move', string='Session Journal Entry', related='session_id.move_id', readonly=True, copy=False) diff --git a/addons/point_of_sale/models/pos_session.py b/addons/point_of_sale/models/pos_session.py index 51751632848..72f7ec32801 100644 --- a/addons/point_of_sale/models/pos_session.py +++ b/addons/point_of_sale/models/pos_session.py @@ -37,8 +37,7 @@ class PosSession(models.Model): 'res.users', string='Opened By', required=True, index=True, - readonly=True, - states={'opening_control': [('readonly', False)]}, + readonly=False, default=lambda self: self.env.uid, ondelete='restrict') currency_id = fields.Many2one('res.currency', related='config_id.currency_id', string="Currency", readonly=False) diff --git a/addons/pos_hr/models/pos_order.py b/addons/pos_hr/models/pos_order.py index f11c6c2e2d2..49e28e5d5ac 100644 --- a/addons/pos_hr/models/pos_order.py +++ b/addons/pos_hr/models/pos_order.py @@ -5,7 +5,7 @@ from odoo import models, fields, api class PosOrder(models.Model): _inherit = "pos.order" - employee_id = fields.Many2one('hr.employee', help="Person who uses the cash register. It can be a reliever, a student or an interim employee.", states={'done': [('readonly', True)], 'invoiced': [('readonly', True)]}) + employee_id = fields.Many2one('hr.employee', help="Person who uses the cash register. It can be a reliever, a student or an interim employee.") cashier = fields.Char(string="Cashier", compute="_compute_cashier", store=True) @api.model diff --git a/addons/pos_online_payment/models/pos_order.py b/addons/pos_online_payment/models/pos_order.py index b5d1810f67a..e49c56ba4c7 100644 --- a/addons/pos_online_payment/models/pos_order.py +++ b/addons/pos_online_payment/models/pos_order.py @@ -8,7 +8,7 @@ class PosOrder(models.Model): _inherit = 'pos.order' online_payment_method_id = fields.Many2one('pos.payment.method', compute="_compute_online_payment_method_id") - next_online_payment_amount = fields.Float(string='Next online payment amount to pay', states={'draft': [('readonly', False)]}, readonly=True, digits=0, required=False) # unlimited precision + next_online_payment_amount = fields.Float(string='Next online payment amount to pay', digits=0, required=False) # unlimited precision @api.depends('config_id.payment_method_ids') def _compute_online_payment_method_id(self): diff --git a/addons/purchase/models/account_invoice.py b/addons/purchase/models/account_invoice.py index b71325a7a67..316160042e0 100644 --- a/addons/purchase/models/account_invoice.py +++ b/addons/purchase/models/account_invoice.py @@ -15,12 +15,10 @@ TOLERANCE = 0.02 # tolerance applied to the total when searching for a matching class AccountMove(models.Model): _inherit = 'account.move' - purchase_vendor_bill_id = fields.Many2one('purchase.bill.union', store=False, readonly=True, - states={'draft': [('readonly', False)]}, + purchase_vendor_bill_id = fields.Many2one('purchase.bill.union', store=False, readonly=False, string='Auto-complete', help="Auto-complete from a past bill / purchase order.") - purchase_id = fields.Many2one('purchase.order', store=False, readonly=True, - states={'draft': [('readonly', False)]}, + purchase_id = fields.Many2one('purchase.order', store=False, readonly=False, string='Purchase Order', help="Auto-complete from a past purchase order.") purchase_order_count = fields.Integer(compute="_compute_origin_po_count", string='Purchase Order Count') diff --git a/addons/purchase/models/purchase.py b/addons/purchase/models/purchase.py index ad1f9dd5372..b7f9639d388 100644 --- a/addons/purchase/models/purchase.py +++ b/addons/purchase/models/purchase.py @@ -73,12 +73,6 @@ class PurchaseOrder(models.Model): order.invoice_ids = invoices order.invoice_count = len(invoices) - READONLY_STATES = { - 'purchase': [('readonly', True)], - 'done': [('readonly', True)], - 'cancel': [('readonly', True)], - } - name = fields.Char('Order Reference', required=True, index='trigram', copy=False, default='New') priority = fields.Selection( [('0', 'Normal'), ('1', 'Urgent')], 'Priority', default='0', index=True) @@ -90,14 +84,14 @@ class PurchaseOrder(models.Model): "It's used to do the matching when you receive the " "products as this reference is usually written on the " "delivery order sent by your vendor.") - date_order = fields.Datetime('Order Deadline', required=True, states=READONLY_STATES, index=True, copy=False, default=fields.Datetime.now, + date_order = fields.Datetime('Order Deadline', required=True, index=True, copy=False, default=fields.Datetime.now, help="Depicts the date within which the Quotation should be confirmed and converted into a purchase order.") date_approve = fields.Datetime('Confirmation Date', readonly=True, index=True, copy=False) - partner_id = fields.Many2one('res.partner', string='Vendor', required=True, states=READONLY_STATES, change_default=True, tracking=True, domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]", help="You can find a vendor by its Name, TIN, Email or Internal Reference.") - dest_address_id = fields.Many2one('res.partner', domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]", string='Dropship Address', states=READONLY_STATES, + partner_id = fields.Many2one('res.partner', string='Vendor', required=True, change_default=True, tracking=True, domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]", help="You can find a vendor by its Name, TIN, Email or Internal Reference.") + dest_address_id = fields.Many2one('res.partner', domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]", string='Dropship Address', help="Put an address if you want to deliver directly from the vendor to the customer. " "Otherwise, keep empty to deliver to your own company.") - currency_id = fields.Many2one('res.currency', 'Currency', required=True, states=READONLY_STATES, + currency_id = fields.Many2one('res.currency', 'Currency', required=True, default=lambda self: self.env.company.currency_id.id) state = fields.Selection([ ('draft', 'RFQ'), @@ -107,7 +101,7 @@ class PurchaseOrder(models.Model): ('done', 'Locked'), ('cancel', 'Cancelled') ], string='Status', readonly=True, index=True, copy=False, default='draft', tracking=True) - order_line = fields.One2many('purchase.order.line', 'order_id', string='Order Lines', states={'cancel': [('readonly', True)], 'done': [('readonly', True)]}, copy=True) + order_line = fields.One2many('purchase.order.line', 'order_id', string='Order Lines', copy=True) notes = fields.Html('Terms and Conditions') invoice_count = fields.Integer(compute="_compute_invoice", string='Bill Count', copy=False, default=0, store=True) @@ -138,13 +132,13 @@ class PurchaseOrder(models.Model): related='company_id.tax_calculation_rounding_method', string='Tax calculation rounding method', readonly=True) payment_term_id = fields.Many2one('account.payment.term', 'Payment Terms', domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]") - incoterm_id = fields.Many2one('account.incoterms', 'Incoterm', states={'done': [('readonly', True)]}, help="International Commercial Terms are a series of predefined commercial terms used in international transactions.") + incoterm_id = fields.Many2one('account.incoterms', 'Incoterm', help="International Commercial Terms are a series of predefined commercial terms used in international transactions.") product_id = fields.Many2one('product.product', related='order_line.product_id', string='Product') user_id = fields.Many2one( 'res.users', string='Buyer', index=True, tracking=True, default=lambda self: self.env.user, check_company=True) - company_id = fields.Many2one('res.company', 'Company', required=True, index=True, states=READONLY_STATES, default=lambda self: self.env.company.id) + company_id = fields.Many2one('res.company', 'Company', required=True, index=True, default=lambda self: self.env.company.id) country_code = fields.Char(related='company_id.account_fiscal_country_id.code', string="Country code") currency_rate = fields.Float("Currency Rate", compute='_compute_currency_rate', compute_sudo=True, store=True, readonly=True, help='Ratio between the purchase order currency and the company currency') diff --git a/addons/purchase_requisition/models/purchase_requisition.py b/addons/purchase_requisition/models/purchase_requisition.py index 606f2ad26e1..db23c16253f 100644 --- a/addons/purchase_requisition/models/purchase_requisition.py +++ b/addons/purchase_requisition/models/purchase_requisition.py @@ -59,8 +59,8 @@ class PurchaseRequisition(models.Model): default=lambda self: self.env.user, check_company=True) description = fields.Html() company_id = fields.Many2one('res.company', string='Company', required=True, default=lambda self: self.env.company) - purchase_ids = fields.One2many('purchase.order', 'requisition_id', string='Purchase Orders', states={'done': [('readonly', True)]}) - line_ids = fields.One2many('purchase.requisition.line', 'requisition_id', string='Products to Purchase', states={'done': [('readonly', True)]}, copy=True) + purchase_ids = fields.One2many('purchase.order', 'requisition_id', string='Purchase Orders') + line_ids = fields.One2many('purchase.requisition.line', 'requisition_id', string='Products to Purchase', copy=True) product_id = fields.Many2one('product.product', related='line_ids.product_id', string='Product') state = fields.Selection(PURCHASE_REQUISITION_STATES, 'Status', tracking=True, required=True, diff --git a/addons/purchase_stock/models/purchase.py b/addons/purchase_stock/models/purchase.py index b9cb60d66c9..19c85e5a0df 100644 --- a/addons/purchase_stock/models/purchase.py +++ b/addons/purchase_stock/models/purchase.py @@ -17,11 +17,11 @@ class PurchaseOrder(models.Model): def _default_picking_type(self): return self._get_picking_type(self.env.context.get('company_id') or self.env.company.id) - incoterm_location = fields.Char(string='Incoterm Location', states={'done': [('readonly', True)]}) + incoterm_location = fields.Char(string='Incoterm Location') incoming_picking_count = fields.Integer("Incoming Shipment count", compute='_compute_incoming_picking_count') picking_ids = fields.Many2many('stock.picking', compute='_compute_picking_ids', string='Receptions', copy=False, store=True) dest_address_id = fields.Many2one('res.partner', compute='_compute_dest_address_id', store=True, readonly=False) - picking_type_id = fields.Many2one('stock.picking.type', 'Deliver To', states=Purchase.READONLY_STATES, required=True, default=_default_picking_type, domain="['|', ('warehouse_id', '=', False), ('warehouse_id.company_id', '=', company_id)]", + picking_type_id = fields.Many2one('stock.picking.type', 'Deliver To', required=True, default=_default_picking_type, domain="['|', ('warehouse_id', '=', False), ('warehouse_id.company_id', '=', company_id)]", help="This will determine operation type of incoming shipment") default_location_dest_id_usage = fields.Selection(related='picking_type_id.default_location_dest_id.usage', string='Destination Location Type', help="Technical field used to display the Drop Ship Address", readonly=True) diff --git a/addons/repair/models/repair.py b/addons/repair/models/repair.py index 4facb47b95a..166e3464c56 100644 --- a/addons/repair/models/repair.py +++ b/addons/repair/models/repair.py @@ -61,8 +61,7 @@ class Repair(models.Model): tag_ids = fields.Many2many('repair.tags', string="Tags") under_warranty = fields.Boolean( 'Under Warranty', - help='If ticked, the sales price will be set to 0 for all products transferred from the repair order.', - states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}) + help='If ticked, the sales price will be set to 0 for all products transferred from the repair order.') schedule_date = fields.Datetime("Scheduled Date", default=fields.Datetime.now, index=True, required=True, copy=False) # Product To Repair @@ -72,15 +71,14 @@ class Repair(models.Model): product_id = fields.Many2one( 'product.product', string='Product to Repair', domain="[('type', 'in', ['product', 'consu']), '|', ('company_id', '=', company_id), ('company_id', '=', False)]", - states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}, check_company=True) + check_company=True) product_qty = fields.Float( 'Product Quantity', - default=1.0, digits='Product Unit of Measure', - readonly=True, states={'draft': [('readonly', False)]}) + default=1.0, digits='Product Unit of Measure') product_uom = fields.Many2one( 'uom.uom', 'Product Unit of Measure', compute='compute_product_uom', store=True, precompute=True, - readonly=True, states={'draft': [('readonly', False)]}, domain="[('category_id', '=', product_uom_category_id)]") + domain="[('category_id', '=', product_uom_category_id)]") product_uom_category_id = fields.Many2one(related='product_id.uom_id.category_id') lot_id = fields.Many2one( 'stock.lot', 'Lot/Serial', diff --git a/addons/sale/models/sale_order.py b/addons/sale/models/sale_order.py index 6533dec7d96..353ccdc956a 100644 --- a/addons/sale/models/sale_order.py +++ b/addons/sale/models/sale_order.py @@ -12,11 +12,6 @@ from odoo.tools.sql import create_index from odoo.addons.payment import utils as payment_utils -READONLY_FIELD_STATES = { - state: [('readonly', True)] - for state in {'sale', 'cancel'} -} - INVOICE_STATUS = [ ('upselling', 'Upselling Opportunity'), ('invoiced', 'Fully Invoiced'), @@ -55,9 +50,8 @@ class SaleOrder(models.Model): name = fields.Char( string="Order Reference", - required=True, copy=False, readonly=True, + required=True, copy=False, readonly=False, index='trigram', - states={'draft': [('readonly', False)]}, default=lambda self: _('New')) company_id = fields.Many2one( @@ -67,9 +61,8 @@ class SaleOrder(models.Model): partner_id = fields.Many2one( comodel_name='res.partner', string="Customer", - required=True, readonly=False, change_default=True, index=True, + required=True, change_default=True, index=True, tracking=1, - states=READONLY_FIELD_STATES, domain="[('company_id', 'in', (False, company_id))]") state = fields.Selection( selection=SALE_ORDER_STATE, @@ -89,8 +82,7 @@ class SaleOrder(models.Model): "this date rather than product lead times.") date_order = fields.Datetime( string="Order Date", - required=True, readonly=False, copy=False, - states=READONLY_FIELD_STATES, + required=True, copy=False, help="Creation date of draft/sent orders,\nConfirmation date of confirmed orders.", default=fields.Datetime.now) origin = fields.Char( @@ -105,13 +97,11 @@ class SaleOrder(models.Model): string="Online Signature", compute='_compute_require_signature', store=True, readonly=False, precompute=True, - states=READONLY_FIELD_STATES, help="Request a online signature and/or payment to the customer in order to confirm orders automatically.") require_payment = fields.Boolean( string="Online Payment", compute='_compute_require_payment', - store=True, readonly=False, precompute=True, - states=READONLY_FIELD_STATES) + store=True, readonly=False, precompute=True) signature = fields.Image( string="Signature", @@ -124,8 +114,7 @@ class SaleOrder(models.Model): validity_date = fields.Date( string="Expiration", compute='_compute_validity_date', - store=True, readonly=False, copy=False, precompute=True, - states=READONLY_FIELD_STATES) + store=True, readonly=False, copy=False, precompute=True) # Partner-based computes note = fields.Html( @@ -159,14 +148,12 @@ class SaleOrder(models.Model): string="Payment Terms", compute='_compute_payment_term_id', store=True, readonly=False, precompute=True, check_company=True, # Unrequired company - states=READONLY_FIELD_STATES, domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]") pricelist_id = fields.Many2one( comodel_name='product.pricelist', string="Pricelist", compute='_compute_pricelist_id', store=True, readonly=False, precompute=True, check_company=True, # Unrequired company - states=READONLY_FIELD_STATES, tracking=1, domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]", help="If you change the pricelist, only newly added lines will be affected.") @@ -250,7 +237,6 @@ class SaleOrder(models.Model): comodel_name='account.analytic.account', string="Analytic Account", copy=False, check_company=True, # Unrequired company - states=READONLY_FIELD_STATES, domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]") tag_ids = fields.Many2many( comodel_name='crm.tag', diff --git a/addons/sale/models/utm_campaign.py b/addons/sale/models/utm_campaign.py index cc7de72b68f..33af74d87e7 100644 --- a/addons/sale/models/utm_campaign.py +++ b/addons/sale/models/utm_campaign.py @@ -11,7 +11,7 @@ class UtmCampaign(models.Model): compute="_compute_quotation_count", compute_sudo=True, groups='sales_team.group_sale_salesman') invoiced_amount = fields.Integer(string="Revenues generated by the campaign", compute="_compute_sale_invoiced_amount", compute_sudo=True, groups='sales_team.group_sale_salesman') - company_id = fields.Many2one('res.company', string='Company', readonly=True, states={'draft': [('readonly', False)], 'refused': [('readonly', False)]}, default=lambda self: self.env.company) + company_id = fields.Many2one('res.company', string='Company', default=lambda self: self.env.company) currency_id = fields.Many2one('res.currency', related='company_id.currency_id', string='Currency') def _compute_quotation_count(self): diff --git a/addons/sale_expense/models/hr_expense.py b/addons/sale_expense/models/hr_expense.py index 536cd75cea6..cc40a78aa12 100644 --- a/addons/sale_expense/models/hr_expense.py +++ b/addons/sale_expense/models/hr_expense.py @@ -8,7 +8,6 @@ class Expense(models.Model): _inherit = "hr.expense" sale_order_id = fields.Many2one('sale.order', compute='_compute_sale_order_id', store=True, string='Customer to Reinvoice', readonly=False, tracking=True, - states={'done': [('readonly', True)], 'refused': [('readonly', True)]}, # NOTE: only confirmed SO can be selected, but this domain in activated throught the name search with the `sale_expense_all_order` # context key. So, this domain is not the one applied. domain="[('state', '=', 'sale'), ('company_id', '=', company_id)]", diff --git a/addons/sale_management/models/sale_order.py b/addons/sale_management/models/sale_order.py index 8b2a6d40def..f9bae843163 100644 --- a/addons/sale_management/models/sale_order.py +++ b/addons/sale_management/models/sale_order.py @@ -7,8 +7,6 @@ from odoo import SUPERUSER_ID, api, fields, models, _ from odoo.exceptions import ValidationError from odoo.tools import is_html_empty -from odoo.addons.sale.models.sale_order import READONLY_FIELD_STATES - class SaleOrder(models.Model): _inherit = 'sale.order' @@ -18,12 +16,10 @@ class SaleOrder(models.Model): string="Quotation Template", compute='_compute_sale_order_template_id', store=True, readonly=False, check_company=True, precompute=True, - states=READONLY_FIELD_STATES, domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]") sale_order_option_ids = fields.One2many( comodel_name='sale.order.option', inverse_name='order_id', string="Optional Products Lines", - states=READONLY_FIELD_STATES, copy=True) #=== COMPUTE METHODS ===# diff --git a/addons/sale_project/models/sale_order.py b/addons/sale_project/models/sale_order.py index db4b6f9224b..ec477f7a9dc 100644 --- a/addons/sale_project/models/sale_order.py +++ b/addons/sale_project/models/sale_order.py @@ -15,8 +15,7 @@ class SaleOrder(models.Model): tasks_count = fields.Integer(string='Tasks', compute='_compute_tasks_ids', groups="project.group_project_user") visible_project = fields.Boolean('Display project', compute='_compute_visible_project', readonly=True) - project_id = fields.Many2one( - 'project.project', 'Project', readonly=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}, + project_id = fields.Many2one('project.project', 'Project', help='Select a non billable project on which tasks can be created.') project_ids = fields.Many2many('project.project', compute="_compute_project_ids", string='Projects', copy=False, groups="project.group_project_user", help="Projects used in this sales order.") project_count = fields.Integer(string='Number of Projects', compute='_compute_project_ids', groups='project.group_project_user') diff --git a/addons/sale_stock/models/sale_order.py b/addons/sale_stock/models/sale_order.py index 04d669bab17..8979822cb3c 100644 --- a/addons/sale_stock/models/sale_order.py +++ b/addons/sale_stock/models/sale_order.py @@ -20,14 +20,12 @@ class SaleOrder(models.Model): picking_policy = fields.Selection([ ('direct', 'As soon as possible'), ('one', 'When all products are ready')], - string='Shipping Policy', required=True, readonly=True, default='direct', - states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}, + string='Shipping Policy', required=True, default='direct', help="If you deliver all products at once, the delivery order will be scheduled based on the greatest " "product lead time. Otherwise, it will be based on the shortest.") warehouse_id = fields.Many2one( 'stock.warehouse', string='Warehouse', required=True, compute='_compute_warehouse_id', store=True, readonly=False, precompute=True, - states={'sale': [('readonly', True)], 'cancel': [('readonly', False)]}, check_company=True) picking_ids = fields.One2many('stock.picking', 'sale_id', string='Transfers') delivery_count = fields.Integer(string='Delivery Orders', compute='_compute_picking_ids') diff --git a/addons/stock/models/stock_move.py b/addons/stock/models/stock_move.py index 1401bdd8c0b..0a0182a09c7 100644 --- a/addons/stock/models/stock_move.py +++ b/addons/stock/models/stock_move.py @@ -45,17 +45,16 @@ class StockMove(models.Model): product_id = fields.Many2one( 'product.product', 'Product', check_company=True, - domain="[('type', 'in', ['product', 'consu'])]", index=True, required=True, - states={'done': [('readonly', True)]}) + domain="[('type', 'in', ['product', 'consu'])]", index=True, required=True) description_picking = fields.Text('Description of Picking') product_qty = fields.Float( - 'Real Quantity', compute='_compute_product_qty', inverse='_set_product_qty', + 'Real Quantity', compute='_compute_product_qty', digits=0, store=True, compute_sudo=True, help='Quantity in the default UoM of the product') product_uom_qty = fields.Float( 'Demand', digits='Product Unit of Measure', - default=0, required=True, states={'done': [('readonly', True)]}, + default=0, required=True, help="This is the quantity of products from an inventory " "point of view. For moves in the state 'done', this is the " "quantity of products that were actually moved. For other " @@ -86,7 +85,6 @@ class StockMove(models.Model): location_dest_usage = fields.Selection(string="Destination Location Type", related='location_dest_id.usage') partner_id = fields.Many2one( 'res.partner', 'Destination Address ', - states={'done': [('readonly', True)]}, help="Optional address where goods are to be delivered, specifically used for allotment", compute='_compute_partner_id', store=True, readonly=False) move_dest_ids = fields.Many2many( @@ -97,7 +95,7 @@ class StockMove(models.Model): 'stock.move', 'stock_move_move_rel', 'move_dest_id', 'move_orig_id', 'Original Move', copy=False, help="Optional: previous stock move when chaining them") - picking_id = fields.Many2one('stock.picking', 'Transfer', index=True, states={'done': [('readonly', True)]}, check_company=True) + picking_id = fields.Many2one('stock.picking', 'Transfer', index=True, check_company=True) state = fields.Selection([ ('draft', 'New'), ('waiting', 'Waiting Another Move'), diff --git a/addons/stock/models/stock_picking.py b/addons/stock/models/stock_picking.py index 3407d239c7e..e9c20d541d8 100644 --- a/addons/stock/models/stock_picking.py +++ b/addons/stock/models/stock_picking.py @@ -294,7 +294,6 @@ class Picking(models.Model): copy=False, index='trigram', readonly=True) origin = fields.Char( 'Source Document', index='trigram', - states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}, help="Reference of the document") note = fields.Html('Notes') backorder_id = fields.Many2one( @@ -311,7 +310,6 @@ class Picking(models.Model): move_type = fields.Selection([ ('direct', 'As soon as possible'), ('one', 'When all products are ready')], 'Shipping Policy', default='direct', required=True, - states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}, help="It specifies goods to be deliver partially or all at once") state = fields.Selection([ ('draft', 'Draft'), @@ -337,7 +335,7 @@ class Picking(models.Model): scheduled_date = fields.Datetime( 'Scheduled Date', compute='_compute_scheduled_date', inverse='_set_scheduled_date', store=True, index=True, default=fields.Datetime.now, tracking=True, - states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}, + readonly=False, help="Scheduled time for the first part of the shipment to be processed. Setting manually a value here would set it as expected date for all the stock moves.") date_deadline = fields.Datetime( "Deadline", compute='_compute_date_deadline', store=True, @@ -348,7 +346,6 @@ class Picking(models.Model): date = fields.Datetime( 'Creation Date', default=fields.Datetime.now, tracking=True, - states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}, help="Creation Date, usually the time of the order") date_done = fields.Datetime('Date of Transfer', copy=False, readonly=True, help="Date at which the transfer has been processed or cancelled.") delay_alert_date = fields.Datetime('Delay Alert Date', compute='_compute_delay_alert_date', search='_search_delay_alert_date') @@ -356,13 +353,11 @@ class Picking(models.Model): location_id = fields.Many2one( 'stock.location', "Source Location", compute="_compute_location_id", store=True, precompute=True, readonly=False, - check_company=True, required=True, - states={'done': [('readonly', True)]}) + check_company=True, required=True) location_dest_id = fields.Many2one( 'stock.location', "Destination Location", compute="_compute_location_id", store=True, precompute=True, readonly=False, - check_company=True, required=True, - states={'done': [('readonly', True)]}) + check_company=True, required=True) move_ids = fields.One2many('stock.move', 'picking_id', string="Stock Moves", copy=True) move_ids_without_package = fields.One2many( 'stock.move', 'picking_id', string="Stock moves not in package", compute='_compute_move_without_package', @@ -382,15 +377,13 @@ class Picking(models.Model): hide_picking_type = fields.Boolean(compute='_compute_hide_picking_type') partner_id = fields.Many2one( 'res.partner', 'Contact', - check_company=True, - states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}) + check_company=True) company_id = fields.Many2one( 'res.company', string='Company', related='picking_type_id.company_id', readonly=True, store=True, index=True) user_id = fields.Many2one( 'res.users', 'Responsible', tracking=True, domain=lambda self: [('groups_id', 'in', self.env.ref('stock.group_stock_user').id)], - states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}, default=lambda self: self.env.user) move_line_ids = fields.One2many('stock.move.line', 'picking_id', 'Operations') move_line_ids_without_package = fields.One2many('stock.move.line', 'picking_id', 'Operations without package', domain=['|',('package_level_id', '=', False), ('picking_type_entire_packs', '=', False)]) @@ -414,7 +407,6 @@ class Picking(models.Model): help='Technical Field used to decide whether the button "Allocation" should be displayed.') owner_id = fields.Many2one( 'res.partner', 'Assign Owner', - states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}, check_company=True, help="When validating the transfer, the products will be assigned to this owner.") printed = fields.Boolean('Printed', copy=False) diff --git a/addons/stock/models/stock_scrap.py b/addons/stock/models/stock_scrap.py index ac8566cf92b..a51b5674b44 100644 --- a/addons/stock/models/stock_scrap.py +++ b/addons/stock/models/stock_scrap.py @@ -15,45 +15,44 @@ class StockScrap(models.Model): name = fields.Char( 'Reference', default=lambda self: _('New'), - copy=False, readonly=True, required=True, - states={'done': [('readonly', True)]}) - company_id = fields.Many2one('res.company', string='Company', default=lambda self: self.env.company, required=True, states={'done': [('readonly', True)]}) + copy=False, required=True) + company_id = fields.Many2one('res.company', string='Company', default=lambda self: self.env.company, required=True) origin = fields.Char(string='Source Document') product_id = fields.Many2one( 'product.product', 'Product', domain="[('type', 'in', ['product', 'consu'])]", - required=True, states={'done': [('readonly', True)]}, check_company=True) + required=True, check_company=True) product_uom_id = fields.Many2one( 'uom.uom', 'Unit of Measure', compute="_compute_product_uom_id", store=True, readonly=False, precompute=True, - required=True, states={'done': [('readonly', True)]}, domain="[('category_id', '=', product_uom_category_id)]") + required=True, domain="[('category_id', '=', product_uom_category_id)]") product_uom_category_id = fields.Many2one(related='product_id.uom_id.category_id') tracking = fields.Selection(string='Product Tracking', readonly=True, related="product_id.tracking") lot_id = fields.Many2one( 'stock.lot', 'Lot/Serial', - states={'done': [('readonly', True)]}, domain="[('product_id', '=', product_id)]", check_company=True) + domain="[('product_id', '=', product_id)]", check_company=True) package_id = fields.Many2one( 'stock.quant.package', 'Package', - states={'done': [('readonly', True)]}, check_company=True) - owner_id = fields.Many2one('res.partner', 'Owner', states={'done': [('readonly', True)]}, check_company=True) + check_company=True) + owner_id = fields.Many2one('res.partner', 'Owner', check_company=True) move_ids = fields.One2many('stock.move', 'scrap_id') - picking_id = fields.Many2one('stock.picking', 'Picking', states={'done': [('readonly', True)]}, check_company=True) + picking_id = fields.Many2one('stock.picking', 'Picking', check_company=True) location_id = fields.Many2one( 'stock.location', 'Source Location', - compute='_compute_location_id', store=True, required=True, precompute=True, states={'done': [('readonly', True)]}, + compute='_compute_location_id', store=True, required=True, precompute=True, domain="[('usage', '=', 'internal')]", check_company=True, readonly=False) scrap_location_id = fields.Many2one( 'stock.location', 'Scrap Location', - compute='_compute_scrap_location_id', store=True, required=True, precompute=True, states={'done': [('readonly', True)]}, + compute='_compute_scrap_location_id', store=True, required=True, precompute=True, domain="[('scrap_location', '=', True)]", check_company=True, readonly=False) scrap_qty = fields.Float( - 'Quantity', required=True, states={'done': [('readonly', True)]}, digits='Product Unit of Measure', + 'Quantity', required=True, digits='Product Unit of Measure', compute='_compute_scrap_qty', default=0.0, readonly=False, store=True) state = fields.Selection([ ('draft', 'Draft'), ('done', 'Done')], string='Status', default="draft", readonly=True, tracking=True) date_done = fields.Datetime('Date', readonly=True) - should_replenish = fields.Boolean(string='Replenish Scrapped Quantities', states={'done': [('readonly', True)]}) + should_replenish = fields.Boolean(string='Replenish Scrapped Quantities') @api.depends('product_id') def _compute_product_uom_id(self): diff --git a/addons/stock_landed_costs/models/stock_landed_cost.py b/addons/stock_landed_costs/models/stock_landed_cost.py index f0a03097918..0bd746bff12 100644 --- a/addons/stock_landed_costs/models/stock_landed_cost.py +++ b/addons/stock_landed_costs/models/stock_landed_cost.py @@ -37,22 +37,21 @@ class StockLandedCost(models.Model): copy=False, readonly=True, tracking=True) date = fields.Date( 'Date', default=fields.Date.context_today, - copy=False, required=True, states={'done': [('readonly', True)]}, tracking=True) + copy=False, required=True, tracking=True) target_model = fields.Selection( [('picking', 'Transfers')], string="Apply On", required=True, default='picking', - copy=False, states={'done': [('readonly', True)]}) + copy=False) picking_ids = fields.Many2many( 'stock.picking', string='Transfers', - copy=False, states={'done': [('readonly', True)]}) + copy=False) cost_lines = fields.One2many( 'stock.landed.cost.lines', 'cost_id', 'Cost Lines', - copy=True, states={'done': [('readonly', True)]}) + copy=True) valuation_adjustment_lines = fields.One2many( - 'stock.valuation.adjustment.lines', 'cost_id', 'Valuation Adjustments', - states={'done': [('readonly', True)]}) + 'stock.valuation.adjustment.lines', 'cost_id', 'Valuation Adjustments',) description = fields.Text( - 'Item Description', states={'done': [('readonly', True)]}) + 'Item Description') amount_total = fields.Monetary( 'Total', compute='_compute_total_amount', store=True, tracking=True) @@ -66,7 +65,7 @@ class StockLandedCost(models.Model): copy=False, readonly=True) account_journal_id = fields.Many2one( 'account.journal', 'Account Journal', - required=True, states={'done': [('readonly', True)]}, default=lambda self: self._default_account_journal_id()) + required=True, default=lambda self: self._default_account_journal_id()) company_id = fields.Many2one('res.company', string="Company", related='account_journal_id.company_id') stock_valuation_layer_ids = fields.One2many('stock.valuation.layer', 'stock_landed_cost_id') diff --git a/addons/stock_picking_batch/models/stock_picking.py b/addons/stock_picking_batch/models/stock_picking.py index dbeb3ef1852..8523dbf5b74 100644 --- a/addons/stock_picking_batch/models/stock_picking.py +++ b/addons/stock_picking_batch/models/stock_picking.py @@ -65,7 +65,6 @@ class StockPicking(models.Model): batch_id = fields.Many2one( 'stock.picking.batch', string='Batch Transfer', check_company=True, - states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}, help='Batch associated to this transfer', index=True, copy=False) @api.model_create_multi diff --git a/addons/stock_picking_batch/models/stock_picking_batch.py b/addons/stock_picking_batch/models/stock_picking_batch.py index 598cf65ea7b..7be6d982a24 100644 --- a/addons/stock_picking_batch/models/stock_picking_batch.py +++ b/addons/stock_picking_batch/models/stock_picking_batch.py @@ -19,14 +19,13 @@ class StockPickingBatch(models.Model): copy=False, required=True, readonly=True) user_id = fields.Many2one( 'res.users', string='Responsible', tracking=True, check_company=True, - readonly=True, states={'draft': [('readonly', False)], 'in_progress': [('readonly', False)]}) + readonly=False) company_id = fields.Many2one( 'res.company', string="Company", required=True, readonly=True, index=True, default=lambda self: self.env.company) picking_ids = fields.One2many( - 'stock.picking', 'batch_id', string='Transfers', readonly=True, + 'stock.picking', 'batch_id', string='Transfers', readonly=False, domain="[('id', 'in', allowed_picking_ids)]", check_company=True, - states={'draft': [('readonly', False)], 'in_progress': [('readonly', False)]}, help='List of transfers associated to this batch') show_check_availability = fields.Boolean( compute='_compute_move_ids', @@ -42,8 +41,7 @@ class StockPickingBatch(models.Model): 'stock.move', string="Stock moves", compute='_compute_move_ids') move_line_ids = fields.One2many( 'stock.move.line', string='Stock move lines', - compute='_compute_move_ids', inverse='_set_move_line_ids', readonly=True, - states={'draft': [('readonly', False)], 'in_progress': [('readonly', False)]}) + compute='_compute_move_ids', inverse='_set_move_line_ids', readonly=False) state = fields.Selection([ ('draft', 'Draft'), ('in_progress', 'In progress'), @@ -53,12 +51,11 @@ class StockPickingBatch(models.Model): copy=False, tracking=True, required=True, readonly=True, index=True) picking_type_id = fields.Many2one( 'stock.picking.type', 'Operation Type', check_company=True, copy=False, - readonly=True, index=True, states={'draft': [('readonly', False)]}) + index=True) picking_type_code = fields.Selection( related='picking_type_id.code') scheduled_date = fields.Datetime( 'Scheduled Date', copy=False, store=True, readonly=False, compute="_compute_scheduled_date", - states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}, help="""Scheduled date for the transfers to be processed. - If manually set then scheduled date for all transfers in batch will automatically update to this date. - If not manually changed and transfers are added/removed/updated then this will be their earliest scheduled date diff --git a/addons/test_base_import/models/test_base_import.py b/addons/test_base_import/models/test_base_import.py index e2441db2330..61cad456a99 100644 --- a/addons/test_base_import/models/test_base_import.py +++ b/addons/test_base_import/models/test_base_import.py @@ -23,23 +23,17 @@ class CharReadonly(models.Model): value = fields.Char(readonly=True) -class CharStates(models.Model): - _name = model('char.states') - _description = 'Tests: Base Import Model, Character states' - - value = fields.Char(readonly=True, states={'draft': [('readonly', False)]}) - class CharNoreadonly(models.Model): _name = model('char.noreadonly') _description = 'Tests: Base Import Model, Character No readonly' - value = fields.Char(readonly=True, states={'draft': [('invisible', True)]}) + value = fields.Char(readonly=True) class CharStillreadonly(models.Model): _name = model('char.stillreadonly') _description = 'Tests: Base Import Model, Character still readonly' - value = fields.Char(readonly=True, states={'draft': [('readonly', True)]}) + value = fields.Char(readonly=True) # TODO: complex field (m2m, o2m, m2o) class M2o(models.Model): diff --git a/addons/test_base_import/security/ir.model.access.csv b/addons/test_base_import/security/ir.model.access.csv index 902d9fbaa1d..673198575b7 100644 --- a/addons/test_base_import/security/ir.model.access.csv +++ b/addons/test_base_import/security/ir.model.access.csv @@ -2,7 +2,6 @@ access_test_base_import_char,base.import.tests.models.char,model_base_import_char,base.group_user,1,1,1,1 access_test_base_import_char_required,base.import.tests.models.char.required,model_base_import_char_required,base.group_user,1,1,1,1 access_test_base_import_char_readonly,base.import.tests.models.char.readonly,model_base_import_char_readonly,base.group_user,1,1,1,1 -access_test_base_import_char_states,base.import.tests.models.char.states,model_base_import_char_states,base.group_user,1,1,1,1 access_test_base_import_char_noreadonly,base.import.tests.models.char.noreadonly,model_base_import_char_noreadonly,base.group_user,1,1,1,1 access_test_base_import_char_stillreadonly,base.import.tests.models.char.stillreadonly,model_base_import_char_stillreadonly,base.group_user,1,1,1,1 access_test_base_import_m2o,base.import.tests.models.m2o,model_base_import_m2o,base.group_user,1,1,1,1 diff --git a/addons/test_base_import/tests/test_base_import.py b/addons/test_base_import/tests/test_base_import.py index de585651e88..d5d407dbf99 100644 --- a/addons/test_base_import/tests/test_base_import.py +++ b/addons/test_base_import/tests/test_base_import.py @@ -71,10 +71,6 @@ class TestBasicFields(BaseImportCase): """ Readonly fields should be filtered out""" self.assertEqualFields(self.get_fields('char.readonly'), [ID_FIELD]) - def test_readonly_states(self): - """ Readonly fields with states should not be filtered out""" - self.assertEqualFields(self.get_fields('char.states'), make_field(field_type='char', model_name=base_import_model('char.states'))) - def test_readonly_states_noreadonly(self): """ Readonly fields with states having nothing to do with readonly should still be filtered out""" diff --git a/odoo/addons/test_new_api/models/test_new_api.py b/odoo/addons/test_new_api/models/test_new_api.py index cfdd3f927d9..17c875fa9bf 100644 --- a/odoo/addons/test_new_api/models/test_new_api.py +++ b/odoo/addons/test_new_api/models/test_new_api.py @@ -1638,9 +1638,7 @@ class PrecomputeReadonly(models.Model): ('confirmed', 'Confirmed'), ], default='draft') bar = fields.Char(compute='_compute_bar', precompute=True, store=True, readonly=True) - baz = fields.Char( - compute='_compute_baz', precompute=True, store=True, readonly=True, states={'draft': [('readonly', False)]} - ) + baz = fields.Char(compute='_compute_baz', precompute=True, store=True, readonly=False) @api.depends('foo') def _compute_bar(self): diff --git a/odoo/addons/test_new_api/tests/test_new_fields.py b/odoo/addons/test_new_api/tests/test_new_fields.py index 2e3f3fc227b..294a3edf0e1 100644 --- a/odoo/addons/test_new_api/tests/test_new_fields.py +++ b/odoo/addons/test_new_api/tests/test_new_fields.py @@ -4605,7 +4605,7 @@ class TestPrecompute(common.TransactionCase): but with a states attributes changing the readonly of the field according to the state of the record, can be altered by the user. The `bar` field is store=True, precompute=True, readonly=True - The `baz` field is store=True, precompute=True, readonly=True, states={'draft': [('readonly', False)]} + The `baz` field is store=True, precompute=True, readonly=False, """ model = self.env['test_new_api.precompute.readonly'] @@ -4621,7 +4621,7 @@ class TestPrecompute(common.TransactionCase): self.assertEqual(record.baz, 'COMPUTED') # no value for bar, value for baz - # baz is readonly=True but states={'draft': [('readonly', False)]} + # baz is readonly=False # the value for baz must be taken into account record = model.create({'foo': 'foo', 'baz': 'baz'}) self.assertEqual(record.bar, 'COMPUTED') diff --git a/odoo/fields.py b/odoo/fields.py index b786688a63b..32a25080f2b 100644 --- a/odoo/fields.py +++ b/odoo/fields.py @@ -544,7 +544,7 @@ class Field(MetaField('DummyField', (object,), {})): warnings.warn(f'Property {self}.readonly should be a boolean ({self.readonly}).') if self.states: - warnings.warn(f'"states" property on the field "{self}" is no longer used', DeprecationWarning) + warnings.warn(f'Since Odoo 17, property {self}.states is no longer supported.') self._setup_done = True @@ -648,8 +648,6 @@ class Field(MetaField('DummyField', (object,), {})): # special cases of inherited fields if self.inherited: self.inherited_field = field - if not self.states: - self.states = field.states if field.required: self.required = True # add modules from delegate and target fields; the first one ensures @@ -904,9 +902,7 @@ class Field(MetaField('DummyField', (object,), {})): def is_editable(self): """ Return whether the field can be editable in a view. """ - return not self.readonly or self.states and any( - 'readonly' in item for items in self.states.values() for item in items - ) + return not self.readonly ############################################################################ # diff --git a/odoo/models.py b/odoo/models.py index 84e41db0cd4..85a9014c358 100644 --- a/odoo/models.py +++ b/odoo/models.py @@ -4326,19 +4326,6 @@ class BaseModel(metaclass=MetaModel): fname for fname, field in self._fields.items() if field.precompute and field.readonly - # ignore `readonly=True` when it's combined with the `states` attribute, - # making the field readonly according to the record state. - # e.g. - # product_uom = fields.Many2one( - # 'uom.uom', 'Product Unit of Measure', - # compute='_compute_product_uom', store=True, precompute=True, - # readonly=True, required=True, states={'draft': [('readonly', False)]}, - # ) - and (not field.states or not any( - modifier == 'readonly' - for modifiers in field.states.values() - for modifier, _value in modifiers - )) ) result_vals_list = []