mirror of
https://github.com/OCA/manufacture.git
synced 2025-01-28 16:37:15 +02:00
79 lines
3.5 KiB
Python
79 lines
3.5 KiB
Python
# Copyright 2023 Quartile Limited
|
|
# Copyright 2024 Tecnativa - Víctor Martínez
|
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
|
|
|
|
from odoo import _, models
|
|
from odoo.exceptions import ValidationError
|
|
from odoo.tools import config, float_compare
|
|
|
|
|
|
class StockMove(models.Model):
|
|
_inherit = "stock.move"
|
|
|
|
def _action_done(self, cancel_backorder=False):
|
|
moves_with_no_check = self.filtered(lambda x: x.is_subcontract).with_context(
|
|
skip_negative_qty_check=True
|
|
)
|
|
# For rather unlikely occassions where linked production is not in the right
|
|
# state.
|
|
for move in moves_with_no_check:
|
|
production_moves = self.search(
|
|
[
|
|
("move_dest_ids", "=", move.id),
|
|
("state", "not in", ("done", "cancel")),
|
|
]
|
|
)
|
|
productions = production_moves.production_id
|
|
unassigned_productions = productions.filtered(
|
|
lambda p: p.reservation_state != "assigned"
|
|
)
|
|
unassigned_productions.action_assign()
|
|
if all(
|
|
state == "assigned"
|
|
for state in unassigned_productions.mapped("reservation_state")
|
|
):
|
|
continue
|
|
moves_with_no_check -= move
|
|
# If you have not been able to allocate previously it is because there is
|
|
# no stock, therefore it will leave the stock negative, we deduct the
|
|
# quantity checking the components and show the corresponding error.
|
|
test_condition = (
|
|
config["test_enable"] and self.env.context.get("test_stock_no_negative")
|
|
) or not config["test_enable"]
|
|
if not test_condition:
|
|
continue
|
|
qty_precision = self.env["decimal.precision"].precision_get(
|
|
"Product Unit of Measure"
|
|
)
|
|
for p_move in unassigned_productions.move_raw_ids.filtered(
|
|
lambda x: x.state != "assigned"
|
|
and not x.product_id.allow_negative_stock
|
|
and not x.product_id.categ_id.allow_negative_stock
|
|
and not x.location_id.allow_negative_stock
|
|
):
|
|
product = p_move.product_id.sudo()
|
|
location = p_move.location_id
|
|
location_qty = product.with_context(location=location.id).free_qty
|
|
new_qty = location_qty - p_move.product_uom_qty
|
|
if float_compare(new_qty, 0, precision_digits=qty_precision) == -1:
|
|
raise ValidationError(
|
|
_(
|
|
"You cannot validate this stock operation because the "
|
|
"stock level of the component product '{name}' would become "
|
|
"negative ({qty}) on the stock location '{location}' and "
|
|
"negative stock is not allowed for this product and/or "
|
|
"location."
|
|
).format(
|
|
name=product.display_name,
|
|
qty=new_qty,
|
|
location=location.complete_name,
|
|
)
|
|
)
|
|
res = super(StockMove, self - moves_with_no_check)._action_done(
|
|
cancel_backorder=cancel_backorder
|
|
)
|
|
res += super(StockMove, moves_with_no_check)._action_done(
|
|
cancel_backorder=cancel_backorder
|
|
)
|
|
return res
|