Files
manufacture/mrp_subcontracting_purchase/models/stock_picking.py
2023-10-13 20:21:22 +04:00

137 lines
5.9 KiB
Python

from datetime import timedelta
from odoo import _, api, fields, models
from odoo.tools.float_utils import float_compare
class StockPicking(models.Model):
_inherit = "stock.picking"
subcontracting_source_purchase_count = fields.Integer(
"Number of subcontracting PO Source",
compute="_compute_subcontracting_source_purchase_count",
help="Number of subcontracting Purchase Order Source",
)
@api.depends("move_lines.move_dest_ids.raw_material_production_id")
def _compute_subcontracting_source_purchase_count(self):
"""Compute number of subcontracting Purchase Order Source"""
for picking in self:
picking.subcontracting_source_purchase_count = len(
picking._get_subcontracting_source_purchase()
)
def action_view_subcontracting_source_purchase(self):
"""Returns action for subcontracting source purchase"""
purchase_order_ids = self._get_subcontracting_source_purchase().ids
action = {
"res_model": "purchase.order",
"type": "ir.actions.act_window",
}
if len(purchase_order_ids) == 1:
action.update(
{
"view_mode": "form",
"res_id": purchase_order_ids[0],
}
)
else:
action.update(
{
"name": _("Source PO of %s") % self.name,
"domain": [("id", "in", purchase_order_ids)],
"view_mode": "tree,form",
}
)
return action
def _get_subcontracting_source_purchase(self):
"""Returns the source purchase order associated with a subcontracted operation."""
moves_subcontracted = self.move_lines.move_dest_ids.raw_material_production_id.move_finished_ids.move_dest_ids.filtered( # noqa
lambda m: m.is_subcontract
)
return moves_subcontracted.purchase_line_id.order_id
def _get_subcontract_production(self):
"""Returns subcontract production in stock picking line"""
return self.move_lines._get_subcontract_production()
def _action_done(self):
# parent function with a subcontract record line added
res = super(StockPicking, self)._action_done()
for move in self.move_lines.filtered(lambda move: move.is_subcontract):
# Auto set qty_producing/lot_producing_id of MO if there isn't tracked component
# If there is tracked component,
# the flow use subcontracting_record_component instead
if move._has_tracked_subcontract_components():
continue
production = move.move_orig_ids.production_id.filtered(
lambda p: p.state not in ("done", "cancel")
)[-1:]
if not production:
continue
# Manage additional quantities
quantity_done_move = move.product_uom._compute_quantity(
move.quantity_done, production.product_uom_id
)
if (
float_compare(
production.product_qty,
quantity_done_move,
precision_rounding=production.product_uom_id.rounding,
)
== -1
):
change_qty = self.env["change.production.qty"].create(
{"mo_id": production.id, "product_qty": quantity_done_move}
)
change_qty.with_context(skip_activity=True).change_prod_qty()
# Create backorder MO for each move lines
for move_line in move.move_line_ids:
if move_line.lot_id:
production.lot_producing_id = move_line.lot_id
production.qty_producing = move_line.product_uom_id._compute_quantity(
move_line.qty_done, production.product_uom_id
)
production._set_qty_producing()
production.subcontracting_has_been_recorded = True
if move_line != move.move_line_ids[-1]:
backorder = production._generate_backorder_productions(
close_mo=False
)
# The move_dest_ids won't be set because the _split filter out done move
backorder.move_finished_ids.filtered(
lambda mo: mo.product_id == move.product_id
).move_dest_ids = production.move_finished_ids.filtered(
lambda mo: mo.product_id == move.product_id
).move_dest_ids
production.product_qty = production.qty_producing
production = backorder
for picking in self:
productions_to_done = (
picking._get_subcontracted_productions()._subcontracting_filter_to_done()
)
if not productions_to_done:
continue
production_ids_backorder = []
if not self.env.context.get("cancel_backorder"):
production_ids_backorder = productions_to_done.filtered(
lambda mo: mo.state == "progress"
).ids
productions_to_done.with_context(
subcontract_move_id=True, mo_ids_to_backorder=production_ids_backorder
).button_mark_done()
# For concistency, set the date on production move before the date
# on picking. (Traceability report + Product Moves menu item)
minimum_date = min(picking.move_line_ids.mapped("date"))
production_moves = (
productions_to_done.move_raw_ids | productions_to_done.move_finished_ids
)
production_moves.write({"date": minimum_date - timedelta(seconds=1)})
production_moves.move_line_ids.write(
{"date": minimum_date - timedelta(seconds=1)}
)
return res