From caa908506b9e186a628cc4ed2d767f74255bad94 Mon Sep 17 00:00:00 2001 From: yhu-odoo Date: Wed, 25 Aug 2021 13:39:10 +0000 Subject: [PATCH] [IMP] mrp,stock: count kits product When a product's has a kits bom, we consider it a kits product. When a product is a kits product, we count its "on hand" and "forecast" qty by caculating how many can be produced according to the bom. We add status button to the show the qty on kit product form. Task-2444000 COM PR odoo/odoo#75555 ENT PR odoo/enterprise#20440 UPG PR odoo/upgrade#2783 Signed-off-by: Arnold Moyaux --- addons/mrp/models/product.py | 39 ++++++++++++++++++++++++++++ addons/mrp/views/product_views.xml | 3 +++ addons/stock/models/product.py | 14 ++++++++++ addons/stock/views/product_views.xml | 13 +++++++--- 4 files changed, 65 insertions(+), 4 deletions(-) diff --git a/addons/mrp/models/product.py b/addons/mrp/models/product.py index d7f27ab3563..fedebc58a02 100644 --- a/addons/mrp/models/product.py +++ b/addons/mrp/models/product.py @@ -22,11 +22,26 @@ class ProductTemplate(models.Model): produce_delay = fields.Float( 'Manufacturing Lead Time', default=0.0, help="Average lead time in days to manufacture this product. In the case of multi-level BOM, the manufacturing lead times of the components will be added.") + is_kits = fields.Boolean(compute='_compute_is_kits', compute_sudo=False) def _compute_bom_count(self): for product in self: product.bom_count = self.env['mrp.bom'].search_count(['|', ('product_tmpl_id', '=', product.id), ('byproduct_ids.product_id.product_tmpl_id', '=', product.id)]) + def _compute_is_kits(self): + domain = [('product_tmpl_id', 'in', self.ids), ('type', '=', 'phantom')] + bom_mapping = self.env['mrp.bom'].search_read(domain, ['product_tmpl_id']) + kits_ids = set(b['product_tmpl_id'][0] for b in bom_mapping) + for template in self: + template.is_kits = (template.id in kits_ids) + + def _compute_show_qty_status_button(self): + super()._compute_show_qty_status_button() + for template in self: + if template.is_kits: + template.show_on_hand_qty_status_button = True + template.show_forecasted_qty_status_button = False + def _compute_used_in_bom_count(self): for template in self: template.used_in_bom_count = self.env['mrp.bom'].search_count( @@ -70,11 +85,35 @@ class ProductProduct(models.Model): compute='_compute_used_in_bom_count', compute_sudo=False) mrp_product_qty = fields.Float('Manufactured', compute='_compute_mrp_product_qty', compute_sudo=False) + is_kits = fields.Boolean(compute="_compute_is_kits", compute_sudo=False) def _compute_bom_count(self): for product in self: product.bom_count = self.env['mrp.bom'].search_count(['|', '|', ('byproduct_ids.product_id', '=', product.id), ('product_id', '=', product.id), '&', ('product_id', '=', False), ('product_tmpl_id', '=', product.product_tmpl_id.id)]) + def _compute_is_kits(self): + domain = ['&', ('type', '=', 'phantom'), + '|', ('product_id', 'in', self.ids), + '&', ('product_id', '=', False), + ('product_tmpl_id', 'in', self.product_tmpl_id.ids)] + bom_mapping = self.env['mrp.bom'].search_read(domain, ['product_tmpl_id', 'product_id']) + kits_template_ids = set([]) + kits_product_ids = set([]) + for bom_data in bom_mapping: + if bom_data['product_id']: + kits_product_ids.add(bom_data['product_id'][0]) + else: + kits_template_ids.add(bom_data['product_tmpl_id'][0]) + for product in self: + product.is_kits = (product.id in kits_product_ids or product.product_tmpl_id.id in kits_template_ids) + + def _compute_show_qty_status_button(self): + super()._compute_show_qty_status_button() + for product in self: + if product.is_kits: + product.show_on_hand_qty_status_button = True + product.show_forecasted_qty_status_button = False + def _compute_used_in_bom_count(self): for product in self: product.used_in_bom_count = self.env['mrp.bom'].search_count([('bom_line_ids.product_id', '=', product.id)]) diff --git a/addons/mrp/views/product_views.xml b/addons/mrp/views/product_views.xml index 2dd6fe52925..81a2057ec38 100644 --- a/addons/mrp/views/product_views.xml +++ b/addons/mrp/views/product_views.xml @@ -13,6 +13,9 @@ days + + + diff --git a/addons/stock/models/product.py b/addons/stock/models/product.py index a49ab7ef607..bac6608fa61 100644 --- a/addons/stock/models/product.py +++ b/addons/stock/models/product.py @@ -97,6 +97,13 @@ class Product(models.Model): compute='_compute_nbr_reordering_rules', compute_sudo=False) putaway_rule_ids = fields.One2many('stock.putaway.rule', 'product_id', 'Putaway Rules') storage_category_capacity_ids = fields.One2many('stock.storage.category.capacity', 'product_id', 'Storage Category Capacity') + show_on_hand_qty_status_button = fields.Boolean(compute='_compute_show_qty_status_button') + show_forecasted_qty_status_button = fields.Boolean(compute='_compute_show_qty_status_button') + + def _compute_show_qty_status_button(self): + for product in self: + product.show_on_hand_qty_status_button = product.product_tmpl_id.show_on_hand_qty_status_button + product.show_forecasted_qty_status_button = product.product_tmpl_id.show_forecasted_qty_status_button @api.depends('stock_move_ids.product_qty', 'stock_move_ids.state') @api.depends_context( @@ -664,6 +671,13 @@ class ProductTemplate(models.Model): route_from_categ_ids = fields.Many2many( relation="stock.location.route", string="Category Routes", related='categ_id.total_route_ids', related_sudo=False) + show_on_hand_qty_status_button = fields.Boolean(compute='_compute_show_qty_status_button') + show_forecasted_qty_status_button = fields.Boolean(compute='_compute_show_qty_status_button') + + def _compute_show_qty_status_button(self): + for template in self: + template.show_on_hand_qty_status_button = template.type == 'product' + template.show_forecasted_qty_status_button = template.type == 'product' @api.depends('type') def _compute_has_available_route_ids(self): diff --git a/addons/stock/views/product_views.xml b/addons/stock/views/product_views.xml index 8f0e98cf84b..980e67291c2 100644 --- a/addons/stock/views/product_views.xml +++ b/addons/stock/views/product_views.xml @@ -250,10 +250,13 @@ attrs="{'invisible': [('type', '!=', 'product')]}"/>
+ +