mirror of
https://github.com/bringout/oca-technical.git
synced 2026-04-18 05:32:02 +02:00
233 lines
8.8 KiB
Python
233 lines
8.8 KiB
Python
# Copyright 2017-24 ForgeFlow S.L. (https://www.forgeflow.com)
|
|
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
|
|
|
import logging
|
|
from datetime import timedelta as td
|
|
|
|
from odoo import api, fields, models
|
|
|
|
from ..models.ddmrp_adjustment import DAF_string, LTAF_string
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
|
class StockBuffer(models.Model):
|
|
_inherit = "stock.buffer"
|
|
|
|
extra_demand_ids = fields.One2many(
|
|
comodel_name="ddmrp.adjustment.demand",
|
|
string="Extra Demand",
|
|
inverse_name="buffer_id",
|
|
help="Demand associated to Demand Adjustment Factors applied to "
|
|
"parent buffers.",
|
|
)
|
|
daf_text = fields.Char(compute="_compute_daf_text")
|
|
parent_daf_text = fields.Char(compute="_compute_daf_text")
|
|
pre_daf_adu = fields.Float(readonly=True)
|
|
daf_applied = fields.Float(default=-1, readonly=True)
|
|
parent_daf_applied = fields.Float(default=-1, readonly=True)
|
|
count_ddmrp_adjustment_demand = fields.Integer(
|
|
compute="_compute_count_ddmrp_adjustment_demand"
|
|
)
|
|
|
|
def _compute_count_ddmrp_adjustment_demand(self):
|
|
for rec in self:
|
|
rec.count_ddmrp_adjustment_demand = len(
|
|
self.env["ddmrp.adjustment.demand"].search(
|
|
[("buffer_origin_id", "=", rec.id)]
|
|
)
|
|
)
|
|
|
|
@api.depends("daf_applied", "parent_daf_applied")
|
|
def _compute_daf_text(self):
|
|
for rec in self:
|
|
rec.daf_text = "DAF: *" + str(round(rec.daf_applied, 2))
|
|
rec.parent_daf_text = "P. DAF: +" + str(round(rec.parent_daf_applied, 2))
|
|
|
|
def _daf_to_apply_domain(self, current=True):
|
|
self.ensure_one()
|
|
today = fields.Date.today()
|
|
domain = [
|
|
("buffer_id", "=", self.id),
|
|
("adjustment_type", "=", DAF_string),
|
|
("date_range_id.date_end", ">=", today),
|
|
]
|
|
if current:
|
|
domain.append(("date_range_id.date_start", "<=", today))
|
|
return domain
|
|
|
|
def _calc_adu(self):
|
|
# Apply DAFs if existing for the buffer.
|
|
res = super()._calc_adu()
|
|
for rec in self:
|
|
self.env["ddmrp.adjustment.demand"].search(
|
|
[("buffer_origin_id", "=", rec.id)]
|
|
).unlink()
|
|
dafs_to_apply = self.env["ddmrp.adjustment"].search(
|
|
rec._daf_to_apply_domain()
|
|
)
|
|
rec.daf_applied = -1
|
|
if dafs_to_apply:
|
|
rec.daf_applied = 1
|
|
values = dafs_to_apply.mapped("value")
|
|
for val in values:
|
|
rec.daf_applied *= val
|
|
rec.pre_daf_adu = rec.adu
|
|
rec.adu *= rec.daf_applied
|
|
_logger.debug(
|
|
"DAF={} applied to {}. ADU: {} -> {}".format(
|
|
rec.daf_applied, rec.name, rec.pre_daf_adu, rec.adu
|
|
)
|
|
)
|
|
# Compute generated demand to be applied to components:
|
|
dafs_to_explode = self.env["ddmrp.adjustment"].search(
|
|
rec._daf_to_apply_domain(False)
|
|
)
|
|
for daf in dafs_to_explode:
|
|
prev = rec.adu
|
|
increased_demand = prev * daf.value - prev
|
|
rec.explode_demand_to_components(daf, increased_demand, rec.product_uom)
|
|
return res
|
|
|
|
def explode_demand_to_components(self, daf, demand, uom_id):
|
|
demand_obj = self.env["ddmrp.adjustment.demand"]
|
|
init_bom = self._get_manufactured_bom()
|
|
if not init_bom:
|
|
return
|
|
|
|
def _get_extra_demand(bom, line, buffer_id, factor):
|
|
qty = factor * line.product_qty / bom.product_qty
|
|
extra = line.product_uom_id._compute_quantity(qty, buffer_id.product_uom)
|
|
return extra
|
|
|
|
def _create_demand(bom, factor=1, level=0, clt=0):
|
|
level += 1
|
|
produce_delay = (
|
|
bom[0].product_id.produce_delay or bom[0].product_tmpl_id.produce_delay
|
|
)
|
|
clt += produce_delay
|
|
for line in bom.bom_line_ids:
|
|
if line.is_buffered:
|
|
buffer_id = line.buffer_id
|
|
extra_demand = _get_extra_demand(bom, line, buffer_id, factor)
|
|
date_start = daf.date_range_id.date_start - td(days=clt)
|
|
date_end = daf.date_range_id.date_end - td(days=clt)
|
|
demand_obj.sudo().create(
|
|
{
|
|
"buffer_id": buffer_id.id,
|
|
"buffer_origin_id": self.id,
|
|
"extra_demand": extra_demand,
|
|
"date_start": date_start,
|
|
"date_end": date_end,
|
|
}
|
|
)
|
|
location = line.location_id
|
|
line_boms = line.product_id.bom_ids
|
|
child_bom = line_boms.filtered(
|
|
lambda bom: bom.location_id == location
|
|
) or line_boms.filtered(lambda b: not b.location_id)
|
|
if child_bom:
|
|
line_qty = line.product_uom_id._compute_quantity(
|
|
line.product_qty, child_bom.product_uom_id
|
|
)
|
|
new_factor = factor * line_qty / bom.product_qty
|
|
_create_demand(child_bom[0], new_factor, level, clt)
|
|
|
|
initial_factor = uom_id._compute_quantity(demand, init_bom.product_uom_id)
|
|
_create_demand(init_bom, factor=initial_factor)
|
|
return True
|
|
|
|
@api.model
|
|
def cron_ddmrp_adu(self, automatic=False):
|
|
"""Apply extra demand originated by Demand Adjustment Factors to
|
|
components after the cron update of all the buffers."""
|
|
res = super().cron_ddmrp_adu(automatic)
|
|
today = fields.Date.today()
|
|
self.search(
|
|
[("parent_daf_applied", "!=", -1), ("extra_demand_ids", "=", False)]
|
|
).write({"parent_daf_applied": -1})
|
|
for op in self.search([("extra_demand_ids", "!=", False)]):
|
|
op.parent_daf_applied = -1
|
|
daf_parent = sum(
|
|
op.extra_demand_ids.filtered(
|
|
lambda r: r.date_start <= today <= r.date_end
|
|
).mapped("extra_demand")
|
|
)
|
|
if daf_parent:
|
|
op.parent_daf_applied = daf_parent
|
|
op.adu += op.parent_daf_applied
|
|
_logger.debug(
|
|
"DAFs-originated demand applied. {}: ADU += {}".format(
|
|
op.name, op.parent_daf_applied
|
|
)
|
|
)
|
|
return res
|
|
|
|
def _ltaf_to_apply_domain(self):
|
|
self.ensure_one()
|
|
today = fields.Date.today()
|
|
return [
|
|
("buffer_id", "=", self.id),
|
|
("adjustment_type", "=", LTAF_string),
|
|
("date_range_id.date_start", "<=", today),
|
|
("date_range_id.date_end", ">=", today),
|
|
]
|
|
|
|
def _compute_dlt(self):
|
|
"""Apply Lead Time Adj Factor if existing"""
|
|
res = super()._compute_dlt()
|
|
for rec in self:
|
|
ltaf_to_apply = self.env["ddmrp.adjustment"].search(
|
|
rec._ltaf_to_apply_domain()
|
|
)
|
|
if ltaf_to_apply:
|
|
ltaf = 1
|
|
values = ltaf_to_apply.mapped("value")
|
|
for val in values:
|
|
ltaf *= val
|
|
prev = rec.dlt
|
|
rec.dlt *= ltaf
|
|
_logger.debug(
|
|
"LTAF=%s applied to %s. DLT: %s -> %s"
|
|
% (ltaf, rec.name, prev, rec.dlt)
|
|
)
|
|
return res
|
|
|
|
def action_archive(self):
|
|
self.env["ddmrp.adjustment.demand"].search(
|
|
[("buffer_origin_id", "in", self.ids)]
|
|
).unlink()
|
|
return super().action_archive()
|
|
|
|
def action_view_demand_to_components(self):
|
|
demand_ids = (
|
|
self.env["ddmrp.adjustment.demand"]
|
|
.search([("buffer_origin_id", "=", self.id)])
|
|
.ids
|
|
)
|
|
action = self.env["ir.actions.act_window"]._for_xml_id(
|
|
"ddmrp_adjustment.ddmrp_adjustment_demand_action"
|
|
)
|
|
action["domain"] = [("id", "in", demand_ids)]
|
|
return action
|
|
|
|
def action_view_affecting_adu(self):
|
|
demand_ids = (
|
|
self.env["ddmrp.adjustment"]
|
|
.search(self._daf_to_apply_domain(current=False))
|
|
.ids
|
|
)
|
|
action = self.env["ir.actions.act_window"]._for_xml_id(
|
|
"ddmrp_adjustment.ddmrp_adjustment_action"
|
|
)
|
|
action["domain"] = [("id", "in", demand_ids)]
|
|
action["context"] = {"search_default_current": 1}
|
|
return action
|
|
|
|
def action_view_parent_affecting_adu(self):
|
|
demand_ids = self.extra_demand_ids.ids
|
|
action = self.env["ir.actions.act_window"]._for_xml_id(
|
|
"ddmrp_adjustment.ddmrp_adjustment_demand_action"
|
|
)
|
|
action["domain"] = [("id", "in", demand_ids)]
|
|
return action
|