mirror of
https://github.com/OCA/stock-logistics-warehouse.git
synced 2025-01-21 14:27:28 +02:00
Transform check at move validation by a constraint on the stock.quant to ensure that the rule is checked in every cases
86 lines
3.4 KiB
Python
86 lines
3.4 KiB
Python
# Copyright 2024 ACSONE SA/NV
|
|
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
|
from collections import defaultdict
|
|
|
|
from odoo import _, api, models
|
|
from odoo.exceptions import ValidationError
|
|
|
|
|
|
class StockQuant(models.Model):
|
|
|
|
_inherit = "stock.quant"
|
|
|
|
@api.constrains("location_id", "product_id")
|
|
def _check_location_product_restriction(self):
|
|
"""
|
|
Check if the quant can be put into the location according to restriction
|
|
defined on the stock_location
|
|
"""
|
|
StockLocation = self.env["stock.location"]
|
|
ProductProduct = self.env["product.product"]
|
|
# We only check quants with a location_id that can
|
|
# only contain the same product
|
|
quants_to_check = self.filtered(
|
|
lambda q: q.location_id.product_restriction == "same"
|
|
)
|
|
if not quants_to_check:
|
|
return
|
|
product_ids_location_id = defaultdict(set)
|
|
error_msgs = []
|
|
for quant in quants_to_check:
|
|
product_ids_location_id[quant.location_id.id].add(quant.product_id.id)
|
|
for location_id, product_ids in product_ids_location_id.items():
|
|
if len(product_ids) > 1:
|
|
location = StockLocation.browse(location_id)
|
|
products = ProductProduct.browse(list(product_ids))
|
|
error_msgs.append(
|
|
_(
|
|
"The location {location} can only contain items of the same "
|
|
"product. You plan to put different products into "
|
|
"this location. ({products})"
|
|
).format(
|
|
location=location.name,
|
|
products=", ".join(products.mapped("name")),
|
|
)
|
|
)
|
|
# Get existing product already in the locations
|
|
SQL = """
|
|
SELECT
|
|
location_id,
|
|
array_agg(distinct(product_id))
|
|
FROM
|
|
stock_quant
|
|
WHERE
|
|
location_id in %s
|
|
GROUP BY
|
|
location_id
|
|
"""
|
|
self.env.cr.execute(SQL, (tuple(quants_to_check.mapped("location_id").ids),))
|
|
existing_product_ids_by_location_id = dict(self.env.cr.fetchall())
|
|
|
|
for (
|
|
location_id,
|
|
existing_product_ids,
|
|
) in existing_product_ids_by_location_id.items():
|
|
product_ids_to_add = product_ids_location_id[location_id]
|
|
if set(existing_product_ids).symmetric_difference(product_ids_to_add):
|
|
location = StockLocation.browse(location_id)
|
|
existing_products = ProductProduct.browse(existing_product_ids)
|
|
to_move_products = ProductProduct.browse(list(product_ids_to_add))
|
|
error_msgs.append(
|
|
_(
|
|
"You plan to add the product {product} into the location {location} "
|
|
"but the location must only contain items of same "
|
|
"product and already contains items of other "
|
|
"product(s) "
|
|
"({existing_products})."
|
|
).format(
|
|
product=" | ".join(to_move_products.mapped("name")),
|
|
location=location.name,
|
|
existing_products=" | ".join(existing_products.mapped("name")),
|
|
)
|
|
)
|
|
|
|
if error_msgs:
|
|
raise ValidationError("\n".join(error_msgs))
|