mirror of
https://github.com/OCA/manufacture.git
synced 2025-01-28 16:37:15 +02:00
137 lines
5.9 KiB
Python
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
|