diff --git a/addons/mrp/models/stock_rule.py b/addons/mrp/models/stock_rule.py index 1c7373c8c1a..9fc2ce20bdd 100644 --- a/addons/mrp/models/stock_rule.py +++ b/addons/mrp/models/stock_rule.py @@ -119,16 +119,19 @@ class StockRule(models.Model): and cumulative description. """ delay, delay_description = super()._get_lead_days(product) + bypass_delay_description = self.env.context.get('bypass_delay_description') manufacture_rule = self.filtered(lambda r: r.action == 'manufacture') if not manufacture_rule: return delay, delay_description manufacture_rule.ensure_one() manufacture_delay = product.produce_delay delay += manufacture_delay - delay_description += '%s+ %d %s' % (_('Manufacturing Lead Time'), manufacture_delay, _('day(s)')) + if not bypass_delay_description: + delay_description += '%s+ %d %s' % (_('Manufacturing Lead Time'), manufacture_delay, _('day(s)')) security_delay = manufacture_rule.picking_type_id.company_id.manufacturing_lead delay += security_delay - delay_description += '%s+ %d %s' % (_('Manufacture Security Lead Time'), security_delay, _('day(s)')) + if not bypass_delay_description: + delay_description += '%s+ %d %s' % (_('Manufacture Security Lead Time'), security_delay, _('day(s)')) return delay, delay_description def _push_prepare_move_copy_values(self, move_to_copy, new_date): diff --git a/addons/product/models/product.py b/addons/product/models/product.py index 91920e7c00b..1250c5cc0f7 100644 --- a/addons/product/models/product.py +++ b/addons/product/models/product.py @@ -598,9 +598,7 @@ class ProductProduct(models.Model): 'target': 'new'} def _prepare_sellers(self, params=False): - # This search is made to avoid retrieving seller_ids from the cache. - return self.env['product.supplierinfo'].search([('product_tmpl_id', '=', self.product_tmpl_id.id), - ('name.active', '=', True)]).sorted(lambda s: (s.sequence, -s.min_qty, s.price, s.id)) + return self.seller_ids.filtered(lambda s: s.name.active).sorted(lambda s: (s.sequence, -s.min_qty, s.price, s.id)) def _select_seller(self, partner_id=False, quantity=0.0, date=None, uom_id=False, params=False): self.ensure_one() @@ -776,7 +774,7 @@ class ProductPackaging(models.Model): class SupplierInfo(models.Model): _name = "product.supplierinfo" _description = "Supplier Pricelist" - _order = 'sequence, min_qty desc, price' + _order = 'sequence, min_qty DESC, price, id' name = fields.Many2one( 'res.partner', 'Vendor', diff --git a/addons/product/models/product_template.py b/addons/product/models/product_template.py index aec908eede4..fd9217256f4 100644 --- a/addons/product/models/product_template.py +++ b/addons/product/models/product_template.py @@ -110,7 +110,7 @@ class ProductTemplate(models.Model): packaging_ids = fields.One2many( 'product.packaging', string="Product Packages", compute="_compute_packaging_ids", inverse="_set_packaging_ids", help="Gives the different ways to package the same product.") - seller_ids = fields.One2many('product.supplierinfo', 'product_tmpl_id', 'Vendors', help="Define vendor pricelists.") + seller_ids = fields.One2many('product.supplierinfo', 'product_tmpl_id', 'Vendors', depends_context=('company',), help="Define vendor pricelists.") variant_seller_ids = fields.One2many('product.supplierinfo', 'product_tmpl_id') active = fields.Boolean('Active', default=True, help="If unchecked, it will allow you to hide the product without removing it.") diff --git a/addons/purchase_stock/models/stock_rule.py b/addons/purchase_stock/models/stock_rule.py index 51c68706d31..2064f76b6e8 100644 --- a/addons/purchase_stock/models/stock_rule.py +++ b/addons/purchase_stock/models/stock_rule.py @@ -148,17 +148,21 @@ class StockRule(models.Model): purpose in order to indicate that those options are available. """ delay, delay_description = super()._get_lead_days(product) + bypass_delay_description = self.env.context.get('bypass_delay_description') buy_rule = self.filtered(lambda r: r.action == 'buy') - if not buy_rule or not product._prepare_sellers(): + seller = product._prepare_sellers() + if not buy_rule or not seller: return delay, delay_description buy_rule.ensure_one() - supplier_delay = product._prepare_sellers()[0].delay - if supplier_delay: + supplier_delay = seller[0].delay + if supplier_delay and not bypass_delay_description: delay_description += '%s+ %d %s' % (_('Vendor Lead Time'), supplier_delay, _('day(s)')) security_delay = buy_rule.picking_type_id.company_id.po_lead - delay_description += '%s+ %d %s' % (_('Purchase Security Lead Time'), security_delay, _('day(s)')) + if not bypass_delay_description: + delay_description += '%s+ %d %s' % (_('Purchase Security Lead Time'), security_delay, _('day(s)')) days_to_purchase = buy_rule.company_id.days_to_purchase - delay_description += '%s+ %d %s' % (_('Days to Purchase'), days_to_purchase, _('day(s)')) + if not bypass_delay_description: + delay_description += '%s+ %d %s' % (_('Days to Purchase'), days_to_purchase, _('day(s)')) return delay + supplier_delay + security_delay + days_to_purchase, delay_description @api.model diff --git a/addons/stock/models/stock_orderpoint.py b/addons/stock/models/stock_orderpoint.py index 6918a6b5d89..6b02cdfbe95 100644 --- a/addons/stock/models/stock_orderpoint.py +++ b/addons/stock/models/stock_orderpoint.py @@ -318,6 +318,8 @@ class StockWarehouseOrderpoint(models.Model): to_remove.unlink() orderpoints = orderpoints - to_remove to_refill = defaultdict(float) + all_product_ids = [] + all_warehouse_ids = [] qty_by_product_warehouse = self.env['report.stock.quantity'].read_group( [('date', '=', fields.date.today()), ('state', '=', 'forecast')], ['product_id', 'product_qty', 'warehouse_id'], @@ -326,6 +328,8 @@ class StockWarehouseOrderpoint(models.Model): warehouse_id = group.get('warehouse_id') and group['warehouse_id'][0] if group['product_qty'] >= 0.0 or not warehouse_id: continue + all_product_ids.append(group['product_id'][0]) + all_warehouse_ids.append(warehouse_id) to_refill[(group['product_id'][0], warehouse_id)] = group['product_qty'] if not to_refill: return action @@ -333,19 +337,27 @@ class StockWarehouseOrderpoint(models.Model): # Recompute the forecasted quantity for missing product today but at this time # with their real lead days. key_to_remove = [] + pwh_per_day = defaultdict(list) for (product, warehouse) in to_refill.keys(): - product = self.env['product.product'].browse(product) - warehouse = self.env['stock.warehouse'].browse(warehouse) + product = self.env['product.product'].browse(product).with_prefetch(all_product_ids) + warehouse = self.env['stock.warehouse'].browse(warehouse).with_prefetch(all_warehouse_ids) rules = product._get_rules_from_location(warehouse.lot_stock_id) - lead_days = rules._get_lead_days(product)[0] - virtual_available = product.with_context( + lead_days = rules.with_context(bypass_delay_description=True)._get_lead_days(product)[0] + pwh_per_day[(lead_days, warehouse)].append(product.id) + # group product by lead_days and warehouse in order to read virtual_available + # in batch + for (days, warehouse), p_ids in pwh_per_day.items(): + products = self.env['product.product'].browse(p_ids) + qties = products.with_context( warehouse=warehouse.id, - to_date=fields.datetime.now() + relativedelta.relativedelta(days=lead_days) - ).virtual_available - if float_compare(virtual_available, 0, precision_rounding=product.uom_id.rounding) >= 0: - key_to_remove.append((product.id, warehouse.id)) - else: - to_refill[(product.id, warehouse.id)] = virtual_available + to_date=fields.datetime.now() + relativedelta.relativedelta(days=days) + ).read(['virtual_available']) + for qty in qties: + if float_compare(qty['virtual_available'], 0, precision_rounding=product.uom_id.rounding) >= 0: + key_to_remove.append((qty['id'], warehouse.id)) + else: + to_refill[(qty['id'], warehouse.id)] = qty['virtual_available'] + for key in key_to_remove: del to_refill[key] if not to_refill: diff --git a/addons/stock/models/stock_rule.py b/addons/stock/models/stock_rule.py index cd78f978567..006415f9303 100644 --- a/addons/stock/models/stock_rule.py +++ b/addons/stock/models/stock_rule.py @@ -330,7 +330,10 @@ class StockRule(models.Model): :rtype: tuple """ delay = sum(self.filtered(lambda r: r.action in ['pull', 'pull_push']).mapped('delay')) - delay_description = ''.join(['%s %s+ %d %s' % (_('Delay on'), html_escape(rule.name), rule.delay, _('day(s)')) for rule in self if rule.action in ['pull', 'pull_push'] and rule.delay]) + if self.env.context.get('bypass_delay_description'): + delay_description = "" + else: + delay_description = ''.join(['%s %s+ %d %s' % (_('Delay on'), html_escape(rule.name), rule.delay, _('day(s)')) for rule in self if rule.action in ['pull', 'pull_push'] and rule.delay]) return delay, delay_description