[FIX] stock, purchase: performance in Replenishement report

Forward port of #70351

closes odoo/odoo#70557

Related: odoo/enterprise#18215
Signed-off-by: Arnold Moyaux <amoyaux@users.noreply.github.com>
Signed-off-by: William Henrotin <Whenrow@users.noreply.github.com>
This commit is contained in:
fw-bot
2021-05-10 08:54:32 +00:00
committed by William Henrotin
parent 0381ca4c7f
commit 84fb0987f2
6 changed files with 43 additions and 23 deletions
+5 -2
View File
@@ -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 += '<tr><td>%s</td><td class="text-right">+ %d %s</td></tr>' % (_('Manufacturing Lead Time'), manufacture_delay, _('day(s)'))
if not bypass_delay_description:
delay_description += '<tr><td>%s</td><td class="text-right">+ %d %s</td></tr>' % (_('Manufacturing Lead Time'), manufacture_delay, _('day(s)'))
security_delay = manufacture_rule.picking_type_id.company_id.manufacturing_lead
delay += security_delay
delay_description += '<tr><td>%s</td><td class="text-right">+ %d %s</td></tr>' % (_('Manufacture Security Lead Time'), security_delay, _('day(s)'))
if not bypass_delay_description:
delay_description += '<tr><td>%s</td><td class="text-right">+ %d %s</td></tr>' % (_('Manufacture Security Lead Time'), security_delay, _('day(s)'))
return delay, delay_description
def _push_prepare_move_copy_values(self, move_to_copy, new_date):
+2 -4
View File
@@ -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',
+1 -1
View File
@@ -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.")
+9 -5
View File
@@ -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 += '<tr><td>%s</td><td class="text-right">+ %d %s</td></tr>' % (_('Vendor Lead Time'), supplier_delay, _('day(s)'))
security_delay = buy_rule.picking_type_id.company_id.po_lead
delay_description += '<tr><td>%s</td><td class="text-right">+ %d %s</td></tr>' % (_('Purchase Security Lead Time'), security_delay, _('day(s)'))
if not bypass_delay_description:
delay_description += '<tr><td>%s</td><td class="text-right">+ %d %s</td></tr>' % (_('Purchase Security Lead Time'), security_delay, _('day(s)'))
days_to_purchase = buy_rule.company_id.days_to_purchase
delay_description += '<tr><td>%s</td><td class="text-right">+ %d %s</td></tr>' % (_('Days to Purchase'), days_to_purchase, _('day(s)'))
if not bypass_delay_description:
delay_description += '<tr><td>%s</td><td class="text-right">+ %d %s</td></tr>' % (_('Days to Purchase'), days_to_purchase, _('day(s)'))
return delay + supplier_delay + security_delay + days_to_purchase, delay_description
@api.model
+22 -10
View File
@@ -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:
+4 -1
View File
@@ -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(['<tr><td>%s %s</td><td class="text-right">+ %d %s</td></tr>' % (_('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(['<tr><td>%s %s</td><td class="text-right">+ %d %s</td></tr>' % (_('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