[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
This commit is contained in:
Gorash
2023-08-18 09:49:11 +02:00
parent 5419d0ef7a
commit 75a105f46a
50 changed files with 152 additions and 290 deletions
+1 -18
View File
@@ -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(
+3 -5
View File
@@ -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')],
@@ -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,
+14 -18
View File
@@ -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,
+8 -15
View File
@@ -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')
@@ -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')
+2 -2
View File
@@ -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
@@ -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')
+4 -4
View File
@@ -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')
@@ -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):
+2 -2
View File
@@ -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):
+2 -2
View File
@@ -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')
@@ -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
@@ -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')
+2 -4
View File
@@ -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')
+5 -5
View File
@@ -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')
+3 -5
View File
@@ -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,
+2 -5
View File
@@ -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,
+9 -10
View File
@@ -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')
+3 -6
View File
@@ -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',
+2 -3
View File
@@ -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):
@@ -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):
+6 -11
View File
@@ -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)
+1 -2
View File
@@ -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)
+1 -1
View File
@@ -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
@@ -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):
+2 -4
View File
@@ -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')
+7 -13
View File
@@ -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')
@@ -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,
+2 -2
View File
@@ -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)
+4 -6
View File
@@ -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',
+5 -19
View File
@@ -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',
+1 -1
View File
@@ -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):
-1
View File
@@ -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)]",
@@ -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 ===#
+1 -2
View File
@@ -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')
+1 -3
View File
@@ -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')
+4 -6
View File
@@ -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'),
+4 -12
View File
@@ -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)
+12 -13
View File
@@ -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):
@@ -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')
@@ -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
@@ -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
@@ -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):
@@ -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
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_test_base_import_char base.import.tests.models.char model_base_import_char base.group_user 1 1 1 1
3 access_test_base_import_char_required base.import.tests.models.char.required model_base_import_char_required base.group_user 1 1 1 1
4 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
5 access_test_base_import_char_noreadonly base.import.tests.models.char.noreadonly model_base_import_char_noreadonly base.group_user 1 1 1 1
6 access_test_base_import_char_stillreadonly base.import.tests.models.char.stillreadonly model_base_import_char_stillreadonly base.group_user 1 1 1 1
7 access_test_base_import_m2o base.import.tests.models.m2o model_base_import_m2o base.group_user 1 1 1 1
@@ -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"""
@@ -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):
@@ -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')
+2 -6
View File
@@ -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
############################################################################
#
-13
View File
@@ -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 = []