diff --git a/addons/base_geolocalize/models/res_config_settings.py b/addons/base_geolocalize/models/res_config_settings.py index 4cd6cdb87da..5cef30c5472 100644 --- a/addons/base_geolocalize/models/res_config_settings.py +++ b/addons/base_geolocalize/models/res_config_settings.py @@ -13,7 +13,7 @@ class ResConfigSettings(models.TransientModel): config_parameter='base_geolocalize.geo_provider', default=lambda x: x.env['base.geocoder']._get_provider() ) - geoloc_provider_techname = fields.Char(related='geoloc_provider_id.tech_name', readonly=1) + geoloc_provider_techname = fields.Char(related='geoloc_provider_id.tech_name', readonly=True) geoloc_provider_googlemap_key = fields.Char( string='Google Map API Key', config_parameter='base_geolocalize.google_map_api_key', diff --git a/addons/hr_holidays/models/hr_leave_accrual_plan_level.py b/addons/hr_holidays/models/hr_leave_accrual_plan_level.py index f31bcc0b1fa..0859e42ffc6 100644 --- a/addons/hr_holidays/models/hr_leave_accrual_plan_level.py +++ b/addons/hr_holidays/models/hr_leave_accrual_plan_level.py @@ -120,7 +120,7 @@ class AccrualPlanLevel(models.Model): [('postponed', 'Transferred to the next year'), ('lost', 'Lost')], string="At the end of the calendar year, unused accruals will be", - default='postponed', required='True') + default='postponed', required=True) postpone_max_days = fields.Integer("Maximum amount of accruals to transfer", help="Set a maximum of days an allocation keeps at the end of the year. 0 for no limit.") diff --git a/addons/iap/models/iap_account.py b/addons/iap/models/iap_account.py index 739d4230635..b1f87a1c663 100644 --- a/addons/iap/models/iap_account.py +++ b/addons/iap/models/iap_account.py @@ -31,7 +31,7 @@ class IapAccount(models.Model): 'iap.account.info', compute='_compute_info', inverse='_inverse_info', search='_search_info') account_info_ids = fields.One2many( 'iap.account.info', 'account_id', - invisible=True, string="Accounts from IAP") + string="Accounts from IAP") balance = fields.Char(compute='_compute_balance') description = fields.Char(related='account_info_id.description') warn_me = fields.Boolean( @@ -247,7 +247,7 @@ class IAPAccountInfo(models.TransientModel): account_id = fields.Many2one('iap.account', string='IAP Account') account_token = fields.Char() balance = fields.Float(string='Balance', digits=(16, 4), default=0) - account_uuid_hashed = fields.Char(string='Account UUID', invisible=True) + account_uuid_hashed = fields.Char(string='Account UUID') service_name = fields.Char(string='Related Service') description = fields.Char() warn_me = fields.Boolean('Warn me', default=False) diff --git a/addons/mail/models/mail_mail.py b/addons/mail/models/mail_mail.py index 5ad42341b2a..cae5291b7cb 100644 --- a/addons/mail/models/mail_mail.py +++ b/addons/mail/models/mail_mail.py @@ -46,7 +46,7 @@ class MailMail(models.Model): mail_message_id_int = fields.Integer(compute='_compute_mail_message_id_int', compute_sudo=True) body_html = fields.Text('Text Contents', help="Rich-text/HTML message") body_content = fields.Html('Rich-text Contents', sanitize=True, compute='_compute_body_content', search="_search_body_content") - references = fields.Text('References', help='Message references, such as identifiers of previous messages', readonly=1) + references = fields.Text('References', help='Message references, such as identifiers of previous messages', readonly=True) headers = fields.Text('Headers', copy=False) restricted_attachment_count = fields.Integer('Restricted attachments', compute='_compute_restricted_attachments') unrestricted_attachment_ids = fields.Many2many('ir.attachment', string='Unrestricted Attachments', @@ -81,7 +81,7 @@ class MailMail(models.Model): ("mail_dup", "Duplicated Email"), ], string='Failure type') failure_reason = fields.Text( - 'Failure Reason', readonly=1, copy=False, + 'Failure Reason', readonly=True, copy=False, help="Failure reason. This is usually the exception thrown by the email server, stored to ease the debugging of mailing issues.") auto_delete = fields.Boolean( 'Auto Delete', diff --git a/addons/mail/models/mail_message.py b/addons/mail/models/mail_message.py index b956e26c534..08166eb11f5 100644 --- a/addons/mail/models/mail_message.py +++ b/addons/mail/models/mail_message.py @@ -163,7 +163,7 @@ class Message(models.Model): reply_to_force_new = fields.Boolean( 'No threading for answers', help='If true, answers do not go in the original document discussion thread. Instead, it will check for the reply_to in tracking message-id and redirected accordingly. This has an impact on the generated message-id.') - message_id = fields.Char('Message-Id', help='Message unique identifier', index='btree', readonly=1, copy=False) + message_id = fields.Char('Message-Id', help='Message unique identifier', index='btree', readonly=True, copy=False) reply_to = fields.Char('Reply-To', help='Reply email address. Setting the reply_to bypasses the automatic thread creation.') mail_server_id = fields.Many2one('ir.mail_server', 'Outgoing mail server') # keep notification layout informations to be able to generate mail again diff --git a/addons/mail/models/mail_thread_blacklist.py b/addons/mail/models/mail_thread_blacklist.py index c7c32fc1b4f..4ce6752c805 100644 --- a/addons/mail/models/mail_thread_blacklist.py +++ b/addons/mail/models/mail_thread_blacklist.py @@ -31,8 +31,7 @@ class MailBlackListMixin(models.AbstractModel): _primary_email = 'email' email_normalized = fields.Char( - string='Normalized Email', compute="_compute_email_normalized", compute_sudo=True, - store=True, invisible=True, + string='Normalized Email', compute="_compute_email_normalized", compute_sudo=True, store=True, help="This field is used to search on email address as the primary email field can contain more than strictly an email address.") # Note : is_blacklisted sould only be used for display. As the compute is not depending on the blacklist, # once read, it won't be re-computed again if the blacklist is modified in the same request. diff --git a/addons/mail/models/mail_tracking_value.py b/addons/mail/models/mail_tracking_value.py index dda8ad0fb30..0a157f81dab 100644 --- a/addons/mail/models/mail_tracking_value.py +++ b/addons/mail/models/mail_tracking_value.py @@ -12,31 +12,31 @@ class MailTracking(models.Model): _rec_name = 'field' _order = 'tracking_sequence asc' - field = fields.Many2one('ir.model.fields', required=True, readonly=1, index=True, ondelete='cascade') - field_desc = fields.Char('Field Description', required=True, readonly=1) + field = fields.Many2one('ir.model.fields', required=True, readonly=True, index=True, ondelete='cascade') + field_desc = fields.Char('Field Description', required=True, readonly=True) field_type = fields.Char('Field Type') field_groups = fields.Char(compute='_compute_field_groups') - old_value_integer = fields.Integer('Old Value Integer', readonly=1) - old_value_float = fields.Float('Old Value Float', readonly=1) - old_value_monetary = fields.Float('Old Value Monetary', readonly=1) - old_value_char = fields.Char('Old Value Char', readonly=1) - old_value_text = fields.Text('Old Value Text', readonly=1) - old_value_datetime = fields.Datetime('Old Value DateTime', readonly=1) + old_value_integer = fields.Integer('Old Value Integer', readonly=True) + old_value_float = fields.Float('Old Value Float', readonly=True) + old_value_monetary = fields.Float('Old Value Monetary', readonly=True) + old_value_char = fields.Char('Old Value Char', readonly=True) + old_value_text = fields.Text('Old Value Text', readonly=True) + old_value_datetime = fields.Datetime('Old Value DateTime', readonly=True) - new_value_integer = fields.Integer('New Value Integer', readonly=1) - new_value_float = fields.Float('New Value Float', readonly=1) - new_value_monetary = fields.Float('New Value Monetary', readonly=1) - new_value_char = fields.Char('New Value Char', readonly=1) - new_value_text = fields.Text('New Value Text', readonly=1) - new_value_datetime = fields.Datetime('New Value Datetime', readonly=1) + new_value_integer = fields.Integer('New Value Integer', readonly=True) + new_value_float = fields.Float('New Value Float', readonly=True) + new_value_monetary = fields.Float('New Value Monetary', readonly=True) + new_value_char = fields.Char('New Value Char', readonly=True) + new_value_text = fields.Text('New Value Text', readonly=True) + new_value_datetime = fields.Datetime('New Value Datetime', readonly=True) currency_id = fields.Many2one('res.currency', 'Currency', readonly=True, ondelete='set null', help="Used to display the currency when tracking monetary values") mail_message_id = fields.Many2one('mail.message', 'Message ID', required=True, index=True, ondelete='cascade') - tracking_sequence = fields.Integer('Tracking field sequence', readonly=1, default=100) + tracking_sequence = fields.Integer('Tracking field sequence', readonly=True, default=100) @api.depends('mail_message_id', 'field') def _compute_field_groups(self): diff --git a/addons/purchase/models/purchase.py b/addons/purchase/models/purchase.py index 7a2cfc4d47e..ad1f9dd5372 100644 --- a/addons/purchase/models/purchase.py +++ b/addons/purchase/models/purchase.py @@ -92,7 +92,7 @@ class PurchaseOrder(models.Model): "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, help="Depicts the date within which the Quotation should be confirmed and converted into a purchase order.") - date_approve = fields.Datetime('Confirmation Date', readonly=1, index=True, copy=False) + 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, help="Put an address if you want to deliver directly from the vendor to the customer. " diff --git a/addons/repair/models/stock_picking.py b/addons/repair/models/stock_picking.py index 9ab65278513..f3cd6b974db 100644 --- a/addons/repair/models/stock_picking.py +++ b/addons/repair/models/stock_picking.py @@ -21,8 +21,7 @@ class PickingType(models.Model): count_repair_late = fields.Integer( string="Number of Repair Orders Late", compute='_compute_count_repair') - default_location_dest_id = fields.Many2one( - readonly={"code", "=", "repair_operation"}) + default_location_dest_id = fields.Many2one() default_remove_location_dest_id = fields.Many2one( 'stock.location', 'Default Remove Destination Location', check_company=True, readonly=True, diff --git a/addons/resource/models/resource_calendar.py b/addons/resource/models/resource_calendar.py index 57094969adf..d0775f553f4 100644 --- a/addons/resource/models/resource_calendar.py +++ b/addons/resource/models/resource_calendar.py @@ -98,7 +98,7 @@ class ResourceCalendar(models.Model): _tz_get, string='Timezone', required=True, default=lambda self: self._context.get('tz') or self.env.user.tz or self.env.ref('base.user_admin').tz or 'UTC', help="This field is used in order to define in which timezone the resources will work.") - tz_offset = fields.Char(compute='_compute_tz_offset', string='Timezone offset', invisible=True) + tz_offset = fields.Char(compute='_compute_tz_offset', string='Timezone offset') two_weeks_calendar = fields.Boolean(string="Calendar in 2 weeks mode") two_weeks_explanation = fields.Char('Explanation', compute="_compute_two_weeks_explanation") diff --git a/addons/sms/wizard/sms_resend.py b/addons/sms/wizard/sms_resend.py index ff8f86deb99..f581c78ea82 100644 --- a/addons/sms/wizard/sms_resend.py +++ b/addons/sms/wizard/sms_resend.py @@ -15,7 +15,7 @@ class SMSRecipient(models.TransientModel): failure_type = fields.Selection( related='notification_id.failure_type', string='Error Message', related_sudo=True, readonly=True) partner_id = fields.Many2one('res.partner', 'Partner', related='notification_id.res_partner_id', readonly=True) - partner_name = fields.Char(string='Recipient Name', readonly='True') + partner_name = fields.Char(string='Recipient Name', readonly=True) sms_number = fields.Char(string='Phone Number') diff --git a/addons/test_website/models/model.py b/addons/test_website/models/model.py index 375e906b085..33c19f386ec 100644 --- a/addons/test_website/models/model.py +++ b/addons/test_website/models/model.py @@ -15,7 +15,7 @@ class TestModel(models.Model): ] _description = 'Website Model Test' - name = fields.Char(required=1) + name = fields.Char(required=True) @api.model def _search_get_detail(self, website, order, options): diff --git a/odoo/addons/base/models/res_partner.py b/odoo/addons/base/models/res_partner.py index 207a1933c6f..e63d2cae079 100644 --- a/odoo/addons/base/models/res_partner.py +++ b/odoo/addons/base/models/res_partner.py @@ -206,7 +206,7 @@ class Partner(models.Model): "If the timezone is not set, UTC (Coordinated Universal Time) is used.\n" "Anywhere else, time values are computed according to the time offset of your web client.") - tz_offset = fields.Char(compute='_compute_tz_offset', string='Timezone offset', invisible=True) + tz_offset = fields.Char(compute='_compute_tz_offset', string='Timezone offset') user_id = fields.Many2one( 'res.users', string='Salesperson', compute='_compute_user_id', diff --git a/odoo/addons/base/models/res_users.py b/odoo/addons/base/models/res_users.py index b9d26496dd6..2e69fe3d8ca 100644 --- a/odoo/addons/base/models/res_users.py +++ b/odoo/addons/base/models/res_users.py @@ -309,8 +309,7 @@ class Users(models.Model): string='Related Partner', help='Partner-related data of the user') login = fields.Char(required=True, help="Used to log into the system") password = fields.Char( - compute='_compute_password', inverse='_set_password', - invisible=True, copy=False, + compute='_compute_password', inverse='_set_password', copy=False, help="Keep empty if you don't want the user to be able to connect on the system.") new_password = fields.Char(string='Set Password', compute='_compute_password', inverse='_set_new_password', @@ -328,7 +327,7 @@ class Users(models.Model): share = fields.Boolean(compute='_compute_share', compute_sudo=True, string='Share User', store=True, help="External user with limited access, created only for the purpose of sharing data.") companies_count = fields.Integer(compute='_compute_companies_count', string="Number of Companies") - tz_offset = fields.Char(compute='_compute_tz_offset', string='Timezone offset', invisible=True) + tz_offset = fields.Char(compute='_compute_tz_offset', string='Timezone offset') res_users_settings_ids = fields.One2many('res.users.settings', 'user_id') # Provide a target for relateds that is not a x2Many field. res_users_settings_id = fields.Many2one('res.users.settings', string="Settings", compute='_compute_res_users_settings_id', search='_search_res_users_settings_id') diff --git a/odoo/fields.py b/odoo/fields.py index 82d15b37492..b786688a63b 100644 --- a/odoo/fields.py +++ b/odoo/fields.py @@ -163,7 +163,7 @@ class Field(MetaField('DummyField', (object,), {})): :type default: value or callable :param dict states: a dictionary mapping state values to lists of UI attribute-value - pairs; possible attributes are: ``readonly``, ``required``, ``invisible``. + pairs; possible attributes are: ``readonly``, ``required``. .. warning:: Any state-based condition requires the ``state`` field value to be available on the client-side UI. This is typically done by including it in @@ -318,7 +318,6 @@ class Field(MetaField('DummyField', (object,), {})): string = None # field label help = None # field tooltip - invisible = False # whether the field is invisible readonly = False # whether the field is readonly required = False # whether the field is required states = None # set readonly and required depending on state @@ -538,6 +537,12 @@ class Field(MetaField('DummyField', (object,), {})): else: self.setup_nonrelated(model) + if not isinstance(self.required, bool): + warnings.warn(f'Property {self}.required should be a boolean ({self.required}).') + + if not isinstance(self.readonly, bool): + 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)