[IMP] mrp{,_subcontracting_purchase}, {purchase_,}stock: add DTPMO to lead days

For subcontracting, we need to consider both vendor lead time and
manufacturing lead time, and DTPMO (Days To Prepare MO) on the BOM.
Subcontracting delay =
    max(Vendor lead time, Manufacturing lead time + DTPMO) + Days to Purchase + Purchase security lead time

Same thing applied to Bom overview, except:
1. Availability state will be computed based on the delay time of it's
   components. DTPMO on the bom won't be take into account.
2. Lead time will use the DTPMO on the BOM. DTPMO will be added to
   the lead time when it's a manufacturing bom or when it's a
   subcontracting bom with Manufacturing Lead Time + DTPMO > Vendor Lead Time

Task-3081481

Part-of: odoo/odoo#137810
This commit is contained in:
yhu-odoo
2023-11-06 13:58:36 +00:00
committed by William Henrotin
parent 6c749a4b0d
commit 78e44dc5a3
17 changed files with 235 additions and 63 deletions
+1 -2
View File
@@ -297,8 +297,7 @@ class MrpBom(models.Model):
warehouse = self.env['stock.warehouse'].search([('company_id', '=', company_id)], limit=1)
for bom in self:
bom_data = self.env['report.mrp.report_bom_structure'].with_context(minimized=True)._get_bom_data(bom, warehouse, bom.product_id, ignore_stock=True)
availability_delay = bom_data.get('resupply_avail_delay')
bom.days_to_prepare_mo = availability_delay - bom_data.get('lead_time', 0) if availability_delay else 0
bom.days_to_prepare_mo = self.env['report.mrp.report_bom_structure']._get_max_component_delay(bom_data['components'])
@api.constrains('product_tmpl_id', 'product_id', 'type')
def check_kit_has_not_orderpoint(self):
-5
View File
@@ -36,8 +36,3 @@ class Company(models.Model):
def _create_per_company_sequences(self):
super(Company, self)._create_per_company_sequences()
self._create_unbuild_sequence()
def _get_security_by_rule_action(self):
res = super()._get_security_by_rule_action()
res['manufacture'] = self.manufacturing_lead
return res
+12 -8
View File
@@ -190,25 +190,29 @@ class StockRule(models.Model):
"""Add the product and company manufacture delay to the cumulative delay
and cumulative description.
"""
delay, delay_description = super()._get_lead_days(product, **values)
delays, delay_description = super()._get_lead_days(product, **values)
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
return delays, delay_description
manufacture_rule.ensure_one()
bom = values.get('bom') or self.env['mrp.bom']._bom_find(product, picking_type=manufacture_rule.picking_type_id, company_id=manufacture_rule.company_id.id)[product]
manufacture_delay = bom.produce_delay
delay += manufacture_delay
delays['total_delay'] += manufacture_delay
delays['manufacture_delay'] += manufacture_delay
if not bypass_delay_description:
delay_description.append((_('Manufacturing Lead Time'), _('+ %d day(s)', manufacture_delay)))
security_delay = manufacture_rule.picking_type_id.company_id.manufacturing_lead
delay += security_delay
if not bypass_delay_description:
delay_description.append((_('Manufacture Security Lead Time'), _('+ %d day(s)', security_delay)))
if bom.type == 'normal':
security_delay = self.picking_type_id.company_id.manufacturing_lead
delays['total_delay'] += security_delay
delays['security_lead_days'] += security_delay
if not bypass_delay_description:
delay_description.append((_('Manufacture Security Lead Time'), _('+ %d day(s)', security_delay)))
days_to_order = values.get('days_to_order', bom.days_to_prepare_mo)
delays['total_delay'] += days_to_order
if not bypass_delay_description:
delay_description.append((_('Days to Supply Components'), _('+ %d day(s)', days_to_order)))
return delay + days_to_order, delay_description
return delays, delay_description
def _push_prepare_move_copy_values(self, move_to_copy, new_date):
new_move_vals = super(StockRule, self)._push_prepare_move_copy_values(move_to_copy, new_date)
@@ -37,18 +37,19 @@ class ReportBomStructure(models.AbstractModel):
@api.model
def _compute_production_capacities(self, bom_qty, bom_data):
date_today = self.env.context.get('from_date', fields.date.today())
same_delay = bom_data['lead_time'] == bom_data['availability_delay']
lead_time = bom_data['lead_time'] - bom_data['bom'].days_to_prepare_mo
same_delay = lead_time == bom_data['availability_delay']
res = {}
if bom_data.get('producible_qty', 0):
# Check if something is producible today, at the earliest time possible considering product's lead time.
res['earliest_capacity'] = bom_data['producible_qty']
res['earliest_date'] = format_date(self.env, date_today + timedelta(days=bom_data['lead_time']))
res['earliest_date'] = format_date(self.env, date_today + timedelta(days=lead_time))
if bom_data['availability_state'] != 'unavailable':
if same_delay:
# Means that stock will be resupplied at date_today, so the whole manufacture can start at date_today.
res['earliest_capacity'] = bom_qty
res['earliest_date'] = format_date(self.env, date_today + timedelta(days=bom_data['lead_time']))
res['earliest_date'] = format_date(self.env, date_today + timedelta(days=bom_data['availability_delay']))
else:
res['leftover_capacity'] = bom_qty - bom_data.get('producible_qty', 0)
res['leftover_date'] = format_date(self.env, date_today + timedelta(days=bom_data['availability_delay']))
@@ -247,7 +248,6 @@ class ReportBomStructure(models.AbstractModel):
'route_type': route_info.get('route_type', ''),
'route_name': route_info.get('route_name', ''),
'route_detail': route_info.get('route_detail', ''),
'lead_time': route_info.get('lead_time', False),
'currency': company.currency_id,
'currency_id': company.currency_id.id,
'product': product,
@@ -314,6 +314,8 @@ class ReportBomStructure(models.AbstractModel):
bom_report_line['bom_cost'] *= bom_report_line['cost_share']
availabilities = self._get_availabilities(product, current_quantity, product_info, bom_key, quantities_info, level, ignore_stock, components, report_line=bom_report_line)
# in case of subcontracting, lead_time will be calculated with components availability delay
bom_report_line['lead_time'] = route_info.get('lead_time', False)
bom_report_line.update(availabilities)
if level == 0:
@@ -588,8 +590,9 @@ class ReportBomStructure(models.AbstractModel):
'route_type': 'manufacture',
'route_name': manufacture_rules[0].route_id.display_name,
'route_detail': bom.display_name,
'lead_time': bom.produce_delay + rules_delay + manufacturing_lead,
'lead_time': bom.produce_delay + rules_delay + manufacturing_lead + bom.days_to_prepare_mo,
'manufacture_delay': bom.produce_delay + rules_delay + manufacturing_lead,
'bom': bom,
}
return {}
@@ -72,15 +72,16 @@ class ReportBomStructure(models.AbstractModel):
subcontract_rules = [rule for rule in rules if rule.action == 'buy' and bom and bom.type == 'subcontract']
if subcontract_rules:
supplier = product._select_seller(quantity=quantity, uom_id=product.uom_id, params={'subcontractor_ids': bom.subcontractor_ids})
# for subcontracting, we can't decide the lead time without component's resupply availability
# we only return necessary info and calculate the lead time late when we have component's data
if supplier:
return {
'route_type': 'subcontract',
'route_name': subcontract_rules[0].route_id.display_name,
'route_detail': supplier.display_name,
'lead_time': supplier.delay + rules_delay,
'supplier_delay': supplier.delay + rules_delay,
'manufacture_delay': bom.produce_delay,
'lead_time': rules_delay,
'supplier': supplier,
'bom': bom,
}
return res
@@ -106,11 +107,16 @@ class ReportBomStructure(models.AbstractModel):
@api.model
def _get_resupply_availability(self, route_info, components):
resupply_state, resupply_delay = super()._get_resupply_availability(route_info, components)
if route_info.get('route_type') == 'subcontract':
max_component_delay = self._get_max_component_delay(components)
if max_component_delay is False:
return ('unavailable', False)
produce_delay = route_info.get('manufacture_delay', 0) + max_component_delay
supplier_delay = route_info.get('supplier_delay', 0)
return ('estimated', max(produce_delay, supplier_delay))
return super()._get_resupply_availability(route_info, components)
# Calculate the lead time for subcontracting, keep same as `_get_lead_days`
vendor_lead_time = route_info['supplier'].delay
manufacture_lead_time = route_info['bom'].produce_delay
subcontract_delay = resupply_delay if resupply_delay else 0
subcontract_delay += max(vendor_lead_time, manufacture_lead_time + max_component_delay)
route_info['lead_time'] += max(vendor_lead_time, manufacture_lead_time + route_info['bom'].days_to_prepare_mo)
return ('estimated', subcontract_delay)
return (resupply_state, resupply_delay)
@@ -2,6 +2,7 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import account_move_line
from . import stock_picking
from . import stock_valuation_layer
from . import purchase_order
from . import stock_picking
from . import stock_rule
from . import stock_valuation_layer
@@ -0,0 +1,50 @@
from odoo import models, _
class StockRule(models.Model):
_inherit = 'stock.rule'
def _get_lead_days(self, product, **values):
"""For subcontracting, we need to consider both vendor lead time and
manufacturing lead time, and DTPMO (Days To Prepare MO).
Subcontracting delay =
max(Vendor lead time, Manufacturing lead time + DTPMO) + Days to Purchase + Purchase security lead time
"""
bypass_delay_description = self.env.context.get('bypass_delay_description')
buy_rule = self.filtered(lambda r: r.action == 'buy')
seller = 'supplierinfo' in values and values['supplierinfo'] or product.with_company(buy_rule.company_id)._select_seller(quantity=None)
if not buy_rule or not seller:
return super()._get_lead_days(product, **values)
seller = seller[0]
bom = self.env['mrp.bom'].sudo()._bom_subcontract_find(
product,
company_id=buy_rule.picking_type_id.company_id.id,
bom_type='subcontract',
subcontractor=seller.partner_id)
if not bom:
return super()._get_lead_days(product, **values)
delays, delay_description = super(StockRule, self - buy_rule)._get_lead_days(product, **values)
extra_delays, extra_delay_description = super(StockRule, buy_rule.with_context(ignore_vendor_lead_time=True))._get_lead_days(product, **values)
if seller.delay >= bom.produce_delay + bom.days_to_prepare_mo:
delays['total_delay'] += seller.delay
delays['purchase_delay'] += seller.delay
if not bypass_delay_description:
delay_description.append((_('Vendor Lead Time'), _('+ %d day(s)', seller.delay)))
else:
manufacture_delay = bom.produce_delay
delays['total_delay'] += manufacture_delay
# set manufacture_delay to purchase_delay so that PO can be created with correct date
delays['purchase_delay'] += manufacture_delay
if not bypass_delay_description:
delay_description.append((_('Manufacturing Lead Time'), _('+ %d day(s)', manufacture_delay)))
days_to_order = bom.days_to_prepare_mo
delays['total_delay'] += days_to_order
# add dtpmo to purchase_delay so that PO can be created with correct date
delays['purchase_delay'] += days_to_order
if not bypass_delay_description:
extra_delay_description.append((_('Days to Supply Components'), _('+ %d day(s)', days_to_order)))
for key, value in extra_delays.items():
delays[key] += value
return delays, delay_description + extra_delay_description
@@ -10,3 +10,14 @@ class ReportBomStructure(models.AbstractModel):
@api.model
def _is_buy_route(self, rules, product, bom):
return super()._is_buy_route(rules, product, bom) and (not bom or bom.type != 'subcontract')
@api.model
def _get_resupply_availability(self, route_info, components):
resupply_state, resupply_delay = super()._get_resupply_availability(route_info, components)
if route_info.get('route_type') == 'subcontract':
# always add `Purchase security lead days` and `Days to Purchase`
extra_delay = route_info['bom'].company_id.po_lead + route_info['bom'].company_id.days_to_purchase
route_info['lead_time'] += extra_delay
subcontract_delay = (resupply_delay if resupply_delay else 0) + extra_delay
return ('estimated', subcontract_delay)
return (resupply_state, resupply_delay)
@@ -382,3 +382,103 @@ class MrpSubcontractingPurchaseTest(TestMrpSubcontractingCommon):
{'location_dest_id': stock_location_id.id, 'quantity': 10.0, 'state': 'done'},
{'location_dest_id': subco_location_id.id, 'quantity': 1.0, 'state': 'done'},
])
def test_subcontracting_lead_days(self):
""" Test the lead days computation for subcontracting. Subcontracting delay =
max(Vendor lead time, Manufacturing lead time + DTPMO) + Days to Purchase + Purchase security lead time
"""
rule = self.env['stock.rule'].search([('action', '=', 'buy')], limit=1)
self.env.company.manufacturing_lead = 114514 # should never be used
self.env.company.po_lead = 1
self.env.company.days_to_purchase = 2
# Case 1 Vendor lead time >= Manufacturing lead time + DTPMO
seller = self.env['product.supplierinfo'].create({
'product_tmpl_id': self.finished.product_tmpl_id.id,
'partner_id': self.subcontractor_partner1.id,
'price': 12.0,
'delay': 10
})
self.bom.produce_delay = 3
self.bom.days_to_prepare_mo = 4
delays, _ = rule._get_lead_days(self.finished, supplierinfo=seller)
self.assertEqual(delays['total_delay'], seller.delay + self.env.company.po_lead + self.env.company.days_to_purchase)
# Case 2 Vendor lead time < Manufacturing lead time + DTPMO
self.bom.produce_delay = 5
self.bom.days_to_prepare_mo = 6
delays, _ = rule._get_lead_days(self.finished, supplierinfo=seller)
self.assertEqual(delays['total_delay'], self.bom.produce_delay + self.bom.days_to_prepare_mo + self.env.company.po_lead + self.env.company.days_to_purchase)
def test_subcontracting_lead_days_on_overview(self):
"""Test on the BOM overview, the lead days and resupply availability are
correctly computed. The dtpmo on the bom should be used for the lead days,
while the resupply availability should be based on the calculated dtpmo.
"""
# should never be used
self.env.company.manufacturing_lead = 114514
# should be added in all cases
self.env.company.po_lead = 5
self.env.company.days_to_purchase = 5
rule = self.env['stock.rule'].search([('action', '=', 'buy')], limit=1)
(self.finished | self.comp1 | self.comp2).route_ids = [(6, None, [rule.route_id.id])]
self.comp2_bom.active = False
self.env['product.supplierinfo'].create({
'product_tmpl_id': self.finished.product_tmpl_id.id,
'partner_id': self.subcontractor_partner1.id,
'price': 648.0,
'delay': 15
})
self.env['product.supplierinfo'].create({
'product_tmpl_id': self.comp1.product_tmpl_id.id,
'partner_id': self.subcontractor_partner1.id,
'price': 648.0,
'delay': 10
})
self.env['product.supplierinfo'].create({
'product_tmpl_id': self.comp2.product_tmpl_id.id,
'partner_id': self.subcontractor_partner1.id,
'price': 648.0,
'delay': 6
})
self.bom.produce_delay = 10
self.bom.days_to_prepare_mo = 0
# Case 1: Vendor lead time >= Manufacturing lead time + DTPMO on BOM
bom_data = self.env['report.mrp.report_bom_structure']._get_bom_data(self.bom, self.warehouse, self.finished)
self.assertEqual(bom_data['lead_time'], 15 + 5 + 5 + 0,
"Lead time = Purchase lead time(finished) + Days to Purchase + Purchase security lead time + DTPMO on BOM")
self.assertEqual(bom_data['resupply_avail_delay'], 10 + 5 + 5 + 20,
"Component avail delay = Purchase lead time(comp1) + Days to Purchase + Purchase security lead time + Calculated DTPMO")
# Case 2: Vendor lead time < Manufacturing lead time + DTPMO on BOM
self.bom.action_compute_bom_days()
self.assertEqual(self.bom.days_to_prepare_mo, 10 + 5 + 5,
"DTPMO = Purchase lead time(comp1) + Days to Purchase + Purchase security lead time")
self.bom.days_to_prepare_mo = 10
bom_data = self.env['report.mrp.report_bom_structure']._get_bom_data(self.bom, self.warehouse, self.finished)
self.assertEqual(bom_data['lead_time'], 10 + 5 + 5 + 10,
"Lead time = Manufacturing lead time + Days to Purchase + Purchase security lead time + DTPMO on BOM")
self.assertEqual(bom_data['resupply_avail_delay'], 10 + 5 + 5 + 20,
"Component avail delay = Manufacturing lead time + Days to Purchase + Purchase security lead time + Calculated DTPMO")
# Update stock for components, calculate DTPMO should be 0
self.env['stock.quant']._update_available_quantity(self.comp1, self.warehouse.lot_stock_id, 100)
self.env['stock.quant']._update_available_quantity(self.comp2, self.warehouse.lot_stock_id, 100)
self.env.invalidate_all() # invalidate cache to get updated qty_available
# Case 1: Vendor lead time >= Manufacturing lead time + DTPMO on BOM
self.bom.days_to_prepare_mo = 2
bom_data = self.env['report.mrp.report_bom_structure']._get_bom_data(self.bom, self.warehouse, self.finished)
self.assertEqual(bom_data['lead_time'], 15 + 5 + 5,
"Lead time = Purchase lead time(finished) + Days to Purchase + Purchase security lead time")
for component in bom_data['components']:
self.assertEqual(component['availability_state'], 'available')
# Case 2: Vendor lead time < Manufacturing lead time + DTPMO on BOM
self.bom.action_compute_bom_days()
self.assertEqual(self.bom.days_to_prepare_mo, 10 + 5 + 5,
"DTPMO = Purchase lead time(comp1) + Days to Purchase + Purchase security lead time")
bom_data = self.env['report.mrp.report_bom_structure']._get_bom_data(self.bom, self.warehouse, self.finished)
self.assertEqual(bom_data['lead_time'], 10 + 5 + 5 + 20,
"Lead time = Manufacturing lead time + Days to Purchase + Purchase security lead time + DTPMO on BOM")
for component in bom_data['components']:
self.assertEqual(component['availability_state'], 'available')
@@ -10,9 +10,3 @@ class ResCompany(models.Model):
days_to_purchase = fields.Float(
string='Days to Purchase',
help="Days needed to confirm a PO, define when a PO should be validated")
def _get_security_by_rule_action(self):
res = super()._get_security_by_rule_action()
res['buy'] = self.po_lead
return res
+14 -8
View File
@@ -161,23 +161,29 @@ class StockRule(models.Model):
and cumulative description. The company lead time is always displayed for onboarding
purpose in order to indicate that those options are available.
"""
delay, delay_description = super()._get_lead_days(product, **values)
delays, delay_description = super()._get_lead_days(product, **values)
bypass_delay_description = self.env.context.get('bypass_delay_description')
buy_rule = self.filtered(lambda r: r.action == 'buy')
seller = 'supplierinfo' in values and values['supplierinfo'] or product.with_company(buy_rule.company_id)._select_seller(quantity=None)
if not buy_rule or not seller:
return delay, delay_description
return delays, delay_description
buy_rule.ensure_one()
supplier_delay = seller[0].delay
if supplier_delay and not bypass_delay_description:
delay_description.append((_('Vendor Lead Time'), _('+ %d day(s)', supplier_delay)))
if not self.env.context.get('ignore_vendor_lead_time'):
supplier_delay = seller[0].delay
delays['total_delay'] += supplier_delay
delays['purchase_delay'] += supplier_delay
if not bypass_delay_description:
delay_description.append((_('Vendor Lead Time'), _('+ %d day(s)', supplier_delay)))
security_delay = buy_rule.picking_type_id.company_id.po_lead
delays['total_delay'] += security_delay
delays['security_lead_days'] += security_delay
if not bypass_delay_description:
delay_description.append((_('Purchase Security Lead Time'), _('+ %d day(s)', security_delay)))
days_to_order = values.get('days_to_order', buy_rule.company_id.days_to_purchase)
days_to_order = buy_rule.company_id.days_to_purchase
delays['total_delay'] += days_to_order
if not bypass_delay_description:
delay_description.append((_('Days to Purchase'), _('+ %d day(s)', days_to_order)))
return delay + supplier_delay + security_delay + days_to_order, delay_description
return delays, delay_description
@api.model
def _get_procurements_to_merge_groupby(self, procurement):
@@ -266,7 +272,7 @@ class StockRule(models.Model):
params values: values of procurements
params origins: procuremets origins to write on the PO
"""
purchase_date = min([fields.Datetime.from_string(value['date_planned']) - relativedelta(days=int(value['supplier'].delay)) for value in values])
purchase_date = min([value.get('date_order') or fields.Datetime.from_string(value['date_planned']) - relativedelta(days=int(value['supplier'].delay)) for value in values])
# Since the procurements are grouped if they share the same domain for
# PO but the PO does not exist. In this case it will create the PO from
+6 -5
View File
@@ -595,12 +595,13 @@ class Product(models.Model):
else:
return self._get_rules_from_location(rule.location_src_id, seen_rules=seen_rules | rule)
def _get_date_with_security_lead_days(self, date, location, route_ids=False):
def _get_dates_info(self, date, location, route_ids=False):
rules = self._get_rules_from_location(location, route_ids=route_ids)
for action, days in location.company_id._get_security_by_rule_action().items():
if action in rules.mapped('action'):
date -= relativedelta(days=days)
return date
delays, _ = rules.with_context(bypass_delay_description=True)._get_lead_days(self)
return {
'date_planned': date - relativedelta(days=delays['security_lead_days']),
'date_order': date - relativedelta(days=delays['security_lead_days'] + delays['purchase_delay']),
}
def _get_only_qty_available(self):
""" Get only quantities available, it is equivalent to read qty_available
-3
View File
@@ -206,6 +206,3 @@ class Company(models.Model):
'partner_id': company.partner_id.id
} for company in companies])
return companies
def _get_security_by_rule_action(self):
return {}
+4 -3
View File
@@ -1407,12 +1407,13 @@ Please change the quantity done or the rounding precision of your unit of measur
elif self.rule_id.group_propagation_option == 'none':
group_id = False
product_id = self.product_id.with_context(lang=self._get_lang())
date = self._get_mto_procurement_date()
dates_info = {'date_planned': self._get_mto_procurement_date()}
if self.location_id.warehouse_id and self.location_id.warehouse_id.lot_stock_id.parent_path in self.location_id.parent_path:
date = self.product_id._get_date_with_security_lead_days(self.date, self.location_id, route_ids=self.route_ids)
dates_info = self.product_id._get_dates_info(self.date, self.location_id, route_ids=self.route_ids)
return {
'product_description_variants': self.description_picking and self.description_picking.replace(product_id._get_description(self.picking_type_id), ''),
'date_planned': date,
'date_planned': dates_info.get('date_planned'),
'date_order': dates_info.get('date_order'),
'date_deadline': self.date_deadline,
'move_dest_ids': self,
'group_id': group_id,
+7 -5
View File
@@ -79,6 +79,7 @@ class StockWarehouseOrderpoint(models.Model):
qty_forecast = fields.Float('Forecast', readonly=True, compute='_compute_qty', digits='Product Unit of Measure')
qty_to_order = fields.Float('To Order', compute='_compute_qty_to_order', store=True, readonly=False, digits='Product Unit of Measure')
#TODO: remove this field in master
days_to_order = fields.Float(compute='_compute_days_to_order', help="Numbers of days in advance that replenishments demands are created.")
visibility_days = fields.Float(
compute='_compute_visibility_days', inverse='_set_visibility_days', readonly=False,
@@ -113,7 +114,7 @@ class StockWarehouseOrderpoint(models.Model):
continue
values = orderpoint._get_lead_days_values()
lead_days, dummy = orderpoint.rule_ids._get_lead_days(orderpoint.product_id, **values)
lead_days_date = fields.Date.today() + relativedelta.relativedelta(days=lead_days)
lead_days_date = fields.Date.today() + relativedelta.relativedelta(days=lead_days['total_delay'])
orderpoint.lead_days_date = lead_days_date
@api.depends('route_id', 'product_id', 'location_id', 'company_id', 'warehouse_id', 'product_id.route_ids')
@@ -352,7 +353,7 @@ class StockWarehouseOrderpoint(models.Model):
# group product by lead_days and location in order to read virtual_available
# in batch
rules = product._get_rules_from_location(loc)
lead_days = rules.with_context(bypass_delay_description=True)._get_lead_days(product)[0]
lead_days = rules.with_context(bypass_delay_description=True)._get_lead_days(product)[0]['total_delay']
ploc_per_day[(lead_days, loc)].add(product.id)
# recompute virtual_available with lead days
@@ -481,11 +482,12 @@ class StockWarehouseOrderpoint(models.Model):
comming from an orderpoint. This method could be override in order to add other custom key that could
be used in move/po creation.
"""
date_planned = date or fields.Date.today()
date_planned = self.product_id._get_date_with_security_lead_days(date_planned, self.location_id, route_ids=self.route_id)
date_deadline = date or fields.Date.today()
dates_info = self.product_id._get_dates_info(date_deadline, self.location_id, route_ids=self.route_id)
return {
'route_ids': self.route_id,
'date_planned': date_planned,
'date_planned': dates_info['date_planned'],
'date_order': dates_info['date_order'],
'date_deadline': date or False,
'warehouse_id': self.warehouse_id,
'orderpoint_id': self,
+5 -3
View File
@@ -359,12 +359,14 @@ class StockRule(models.Model):
:param product: the product of the procurement
:type product: :class:`~odoo.addons.product.models.product.ProductProduct`
:return: the cumulative delay and cumulative delay's description
:rtype: tuple[int, list[str, str]]
:rtype: tuple[defaultdict(float), list[str, str]]
"""
delays = defaultdict(float)
delay = sum(self.filtered(lambda r: r.action in ['pull', 'pull_push']).mapped('delay'))
delays['total_delay'] += delay
global_visibility_days = self.env['ir.config_parameter'].sudo().get_param('stock.visibility_days')
if global_visibility_days:
delay += int(global_visibility_days)
delays['total_delay'] += int(global_visibility_days)
if self.env.context.get('bypass_delay_description'):
delay_description = []
else:
@@ -375,7 +377,7 @@ class StockRule(models.Model):
]
if global_visibility_days:
delay_description.append((_('Global Visibility Days'), _('+ %d day(s)', int(global_visibility_days))))
return delay, delay_description
return delays, delay_description
class ProcurementGroup(models.Model):
@@ -118,7 +118,7 @@ class StockReplenishmentOption(models.TransientModel):
@api.depends('replenishment_info_id')
def _compute_lead_time(self):
for record in self:
lead_time = record.route_id.rule_ids._get_lead_days(record.product_id)[0]
lead_time = record.route_id.rule_ids._get_lead_days(record.product_id)[0]['total_delay'] #TO FIX: use _get_rule to avoid singleton issue
record.lead_time = str(lead_time) + " days"
@api.depends('warehouse_id', 'free_qty', 'uom', 'qty_to_order')