[REF] stock,purchase(_*),mrp: clean related fields

Related fields are by default readonly and they should be when it
is possible. A editable related field will write on the related
model and will cause extra unwanted write of data. These unwanted write
can cause performance issues in some case (see odoo/odoo#63865).

Then remove the `readonly=False` of some related fields
(where it is useless):

- In 'mrp.workorder' (mrp): `working_state` and `production_date`
should be readonly.
- In 'purchase.order' (purchase): `product_id` should be readonly.
- In 'purchase.order.line' (purchase): `state` should be readonly.
- In 'product.supplierinfo' (purchase_requisition):
`purchase_requisition_id` should be readonly.
- In 'purchase.requisition' (purchase_requisition):
`product_id` should be readonly.
- In 'product.template' (stock):
`route_from_categ_ids` should be readonly.
- In 'stock.move.line' (stock):
`is_initial_demand_editable` should be readonly.
- In 'stock.move' (stock):
`product_tmpl_id` should be readonly.
- In 'stock.production.lot' (stock):
`product_uom_id` should be readonly.
- In 'stock.quant' (stock):
`product_tmpl_id` should be readonly.
- In 'stock.rule' (stock):
`route_sequence` should be readonly.
- In 'stock.change.product.qty' (stock):
`product_variant_count` should be readonly.
- In 'stock.return.picking.line' (stock):
`uom_id` should be readonly and also because it
is forced by `_prepare_stock_return_picking_line_vals_from_move`,
it should be related to the product uom not the one on the move.

task-2424248
This commit is contained in:
Rémy Voet (ryv)
2021-01-21 11:09:58 +00:00
parent ecdde54c5a
commit bec794f776
17 changed files with 19 additions and 20 deletions
+2 -2
View File
@@ -29,7 +29,7 @@ class MrpWorkorder(models.Model):
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', readonly=False,
string='Workcenter Status', related='workcenter_id.working_state',
help='Technical: used in views only')
product_id = fields.Many2one(related='production_id.product_id', readonly=True, store=True, check_company=True)
product_tracking = fields.Selection(related="product_id.tracking")
@@ -137,7 +137,7 @@ class MrpWorkorder(models.Model):
next_work_order_id = fields.Many2one('mrp.workorder', "Next Work Order", check_company=True)
scrap_ids = fields.One2many('stock.scrap', 'workorder_id')
scrap_count = fields.Integer(compute='_compute_scrap_move_count', string='Scrap Move')
production_date = fields.Datetime('Production Date', related='production_id.date_planned_start', store=True, readonly=False)
production_date = fields.Datetime('Production Date', related='production_id.date_planned_start', store=True)
json_popover = fields.Char('Popover Data JSON', compute='_compute_json_popover')
show_json_popover = fields.Boolean('Show Popover?', compute='_compute_json_popover')
consumption = fields.Selection(related='production_id.consumption')
+2 -2
View File
@@ -122,7 +122,7 @@ class PurchaseOrder(models.Model):
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.")
product_id = fields.Many2one('product.product', related='order_line.product_id', string='Product', readonly=False)
product_id = fields.Many2one('product.product', related='order_line.product_id', string='Product')
user_id = fields.Many2one(
'res.users', string='Purchase Representative', index=True, tracking=True,
default=lambda self: self.env.user, check_company=True)
@@ -821,7 +821,7 @@ class PurchaseOrderLine(models.Model):
account_analytic_id = fields.Many2one('account.analytic.account', store=True, string='Analytic Account', compute='_compute_analytic_id_and_tag_ids', readonly=False)
analytic_tag_ids = fields.Many2many('account.analytic.tag', store=True, string='Analytic Tags', compute='_compute_analytic_id_and_tag_ids', readonly=False)
company_id = fields.Many2one('res.company', related='order_id.company_id', string='Company', store=True, readonly=True)
state = fields.Selection(related='order_id.state', store=True, readonly=False)
state = fields.Selection(related='order_id.state', store=True)
invoice_lines = fields.One2many('account.move.line', 'purchase_line_id', string="Bill Lines", readonly=True, copy=False)
+1 -1
View File
@@ -219,7 +219,7 @@
</control>
<field name="display_type" invisible="1"/>
<field name="currency_id" invisible="1"/>
<field name="state" invisible="1" readonly="1"/>
<field name="state" invisible="1"/>
<field name="product_type" invisible="1"/>
<field name="product_uom_category_id" invisible="1"/>
<field name="invoice_lines" invisible="1"/>
@@ -7,7 +7,7 @@ from odoo import fields, models
class SupplierInfo(models.Model):
_inherit = 'product.supplierinfo'
purchase_requisition_id = fields.Many2one('purchase.requisition', related='purchase_requisition_line_id.requisition_id', string='Agreement', readonly=False)
purchase_requisition_id = fields.Many2one('purchase.requisition', related='purchase_requisition_line_id.requisition_id', string='Agreement')
purchase_requisition_line_id = fields.Many2one('purchase.requisition.line')
@@ -60,7 +60,7 @@ class PurchaseRequisition(models.Model):
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)
product_id = fields.Many2one('product.product', related='line_ids.product_id', string='Product', readonly=False)
product_id = fields.Many2one('product.product', related='line_ids.product_id', string='Product')
state = fields.Selection(PURCHASE_REQUISITION_STATES,
'Status', tracking=True, required=True,
copy=False, default='draft')
@@ -7,7 +7,7 @@
<field name="inherit_id" ref="product.product_supplierinfo_tree_view"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='product_id']" position="after">
<field name="purchase_requisition_id" readonly="1" optional="hide"/>
<field name="purchase_requisition_id" optional="hide"/>
</xpath>
</field>
</record>
+1 -1
View File
@@ -599,7 +599,7 @@ class ProductTemplate(models.Model):
# TDE FIXME: seems only visible in a view - remove me ?
route_from_categ_ids = fields.Many2many(
relation="stock.location.route", string="Category Routes",
related='categ_id.total_route_ids', readonly=False, related_sudo=False)
related='categ_id.total_route_ids', related_sudo=False)
@api.depends('type')
def _compute_has_available_route_ids(self):
+1 -1
View File
@@ -69,7 +69,7 @@ class StockMove(models.Model):
# TDE FIXME: make it stored, otherwise group will not work
product_tmpl_id = fields.Many2one(
'product.template', 'Product Template',
related='product_id.product_tmpl_id', readonly=False,
related='product_id.product_tmpl_id',
help="Technical: used in views")
location_id = fields.Many2one(
'stock.location', 'Source Location',
+1 -1
View File
@@ -61,7 +61,7 @@ class StockMoveLine(models.Model):
picking_type_use_existing_lots = fields.Boolean(related='picking_id.picking_type_id.use_existing_lots', readonly=True)
picking_type_entire_packs = fields.Boolean(related='picking_id.picking_type_id.show_entire_packs', readonly=True)
state = fields.Selection(related='move_id.state', store=True, related_sudo=False)
is_initial_demand_editable = fields.Boolean(related='move_id.is_initial_demand_editable', readonly=False)
is_initial_demand_editable = fields.Boolean(related='move_id.is_initial_demand_editable')
is_locked = fields.Boolean(related='move_id.is_locked', default=True, readonly=True)
consume_line_ids = fields.Many2many('stock.move.line', 'stock_move_line_consume_rel', 'consume_line_id', 'produce_line_id', help="Technical link to see who consumed what. ")
produce_line_ids = fields.Many2many('stock.move.line', 'stock_move_line_consume_rel', 'produce_line_id', 'consume_line_id', help="Technical link to see which line was produced with this. ")
+1 -1
View File
@@ -20,7 +20,7 @@ class ProductionLot(models.Model):
domain=lambda self: self._domain_product_id(), required=True, check_company=True)
product_uom_id = fields.Many2one(
'uom.uom', 'Unit of Measure',
related='product_id.uom_id', store=True, readonly=False)
related='product_id.uom_id', store=True)
quant_ids = fields.One2many('stock.quant', 'lot_id', 'Quants', readonly=True)
product_qty = fields.Float('Quantity', compute='_product_qty')
note = fields.Html(string='Description')
+1 -1
View File
@@ -56,7 +56,7 @@ class StockQuant(models.Model):
ondelete='restrict', readonly=True, required=True, index=True, check_company=True)
product_tmpl_id = fields.Many2one(
'product.template', string='Product Template',
related='product_id.product_tmpl_id', readonly=False)
related='product_id.product_tmpl_id')
product_uom_id = fields.Many2one(
'uom.uom', 'Unit of Measure',
readonly=True, related='product_id.uom_id')
+1 -1
View File
@@ -64,7 +64,7 @@ class StockRule(models.Model):
"Trigger Another Rule: the system will try to find a stock rule to bring the products in the source location. The available stock will be ignored.\n"
"Take From Stock, if Unavailable, Trigger Another Rule: the products will be taken from the available stock of the source location."
"If there is no stock available, the system will try to find a rule to bring the products in the source location.")
route_sequence = fields.Integer('Route Sequence', related='route_id.sequence', store=True, readonly=False, compute_sudo=True)
route_sequence = fields.Integer('Route Sequence', related='route_id.sequence', store=True, compute_sudo=True)
picking_type_id = fields.Many2one(
'stock.picking.type', 'Operation Type',
required=True, check_company=True,
+1 -1
View File
@@ -115,7 +115,7 @@
attrs="{'invisible':[('type', 'not in', ['product', 'consu'])]}"
class="btn btn-link pt-0" context="{'default_product_tmpl_id': id}"/>
</div>
<field name="route_from_categ_ids" widget="many2many_tags" readonly="1" attrs="{'invisible': [('route_from_categ_ids', '=', [])]}"/>
<field name="route_from_categ_ids" widget="many2many_tags" attrs="{'invisible': [('route_from_categ_ids', '=', [])]}"/>
</group>
</xpath>
<xpath expr="//group[@name='group_lots_and_weight']" position="after">
@@ -25,7 +25,7 @@
<label for="product_qty" attrs="{'invisible': [('display_complete', '=', False)]}"/>
<div class="o_row" attrs="{'invisible': [('display_complete', '=', False)]}">
<field name="product_qty"/>
<field name="product_uom_id" readonly="1" groups="uom.group_uom"/>
<field name="product_uom_id" groups="uom.group_uom"/>
</div>
<field name="ref"/>
<field name="company_id" groups="base.group_multi_company"/>
@@ -11,8 +11,7 @@ class ProductChangeQuantity(models.TransientModel):
product_id = fields.Many2one('product.product', 'Product', required=True)
product_tmpl_id = fields.Many2one('product.template', 'Template', required=True)
product_variant_count = fields.Integer('Variant Count',
related='product_tmpl_id.product_variant_count', readonly=False)
product_variant_count = fields.Integer('Variant Count', related='product_tmpl_id.product_variant_count')
new_quantity = fields.Float(
'New Quantity on Hand', default=1,
digits='Product Unit of Measure', required=True,
+1 -1
View File
@@ -13,7 +13,7 @@ class ReturnPickingLine(models.TransientModel):
product_id = fields.Many2one('product.product', string="Product", required=True, domain="[('id', '=', product_id)]")
quantity = fields.Float("Quantity", digits='Product Unit of Measure', required=True)
uom_id = fields.Many2one('uom.uom', string='Unit of Measure', related='move_id.product_uom', readonly=False)
uom_id = fields.Many2one('uom.uom', string='Unit of Measure', related='product_id.uom_id')
wizard_id = fields.Many2one('stock.return.picking', string="Wizard")
move_id = fields.Many2one('stock.move', "Move")
@@ -24,7 +24,7 @@
<tree editable="top" create="0">
<field name="product_id" options="{'no_create': True, 'no_open': True}" force_save="1"/>
<field name="quantity"/>
<field name="uom_id" readonly="1" groups="uom.group_uom"/>
<field name="uom_id" groups="uom.group_uom"/>
<field name="move_id" invisible="1"/>
</tree>
</field>