Merge PR #1954 into 16.0

Signed-off-by sebalix
This commit is contained in:
OCA-git-bot
2024-03-05 11:15:39 +00:00
8 changed files with 114 additions and 45 deletions

View File

@@ -1,2 +1,3 @@
from . import product_product
from . import stock_move
from . import stock_picking

View File

@@ -0,0 +1,27 @@
# Copyright 2023 Michael Tietz (MT Software) <mtietz@mt-software.de>
# Copyright 2023 ACSONE SA/NV
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import models
class ProductProduct(models.Model):
_inherit = "product.product"
def _get_volume_for_qty(self, qty, from_uom=None):
"""Return the volume for the given qty.
This method is meant to be inherited to change the volume
computation for a specific product.
qty: float quantity to compute the volume for.
from_uom: uom of given qty
An override of this method could take into account the packaging
of the product to compute the volume. (using the volume information
on the packaging provided by the module stock_quant_package_dimension
and the method product_qty_by_packaging on the product provided by the
module stock_packaging_calculator)
"""
self.ensure_one()
qty = from_uom and from_uom._compute_quantity(qty, self.uom_id) or qty
return qty * self.volume

View File

@@ -26,27 +26,10 @@ class StockMove(models.Model):
qty = move.product_uom_qty
if move.state in ("partially_available", "assigned"):
qty = move.reserved_availability
new_volume = move._get_volume_for_qty(qty=qty)
new_volume = move.product_id._get_volume_for_qty(qty, move.product_uom)
if move.volume != new_volume:
move.volume = new_volume
def _get_volume_for_qty(self, qty):
"""Return the volume for the move.
This method is meant to be inherited to change the volume
computation for a specific move.
qty: float quantity to compute the volume for.
An override of this method could take into account the packaging
of the product to compute the volume. (using the volume information
on the packaging provided by the module stock_quant_package_dimension
and the method product_qty_by_packaging on the product provided by the
module stock_packaging_calculator)
"""
self.ensure_one()
return qty * self.product_id.volume
def _compute_volume_uom_name(self):
self.volume_uom_name = self.env[
"product.template"

View File

@@ -19,12 +19,18 @@ class StockPicking(models.Model):
string="Volume unit of measure label", compute="_compute_volume_uom_name"
)
@api.depends("move_ids", "move_ids.volume")
@api.depends("move_ids", "move_ids.volume", "move_ids.state")
def _compute_volume(self):
for picking in self:
new_volume = sum(picking.move_ids.mapped("volume"))
if picking.volume != new_volume:
picking.volume = new_volume
moves = picking.move_ids
exclude_cancel = any(m.state != "cancel" for m in moves)
volume = 0
for move in moves:
if move.state == "cancel" and exclude_cancel:
continue
volume += move.volume
if picking.volume != volume:
picking.volume = volume
def _compute_volume_uom_name(self):
self.volume_uom_name = self.env[

View File

@@ -19,17 +19,7 @@ class TestStockPickingVolume(TransactionCase):
)
cls.loc_stock = cls.wh.lot_stock_id
cls.loc_customer = cls.env.ref("stock.stock_location_customers")
cls.product_template = cls.env["product.template"].create(
{
"name": "Unittest P1",
"product_length": 10.0,
"product_width": 5.0,
"product_height": 3.0,
"uom_id": cls.env.ref("uom.product_uom_unit").id,
"type": "product",
}
)
cls.product = cls.product_template.product_variant_ids
cls.product = cls._create_product("Unittest P1", 10.0, 5.0, 3.0)
cls.picking_type_out = cls.env.ref("stock.picking_type_out")
cls.picking = cls.env["stock.picking"].create(
{
@@ -53,6 +43,21 @@ class TestStockPickingVolume(TransactionCase):
}
)
@classmethod
def _create_product(cls, name, length, width, height):
product = cls.env["product.product"].create(
{
"name": name,
"product_length": length,
"product_width": width,
"product_height": height,
"uom_id": cls.env.ref("uom.product_uom_unit").id,
"dimensional_uom_id": cls.env.ref("uom.product_uom_meter").id,
"type": "product",
}
)
return product
def _set_product_qty(self, product, qty):
self.env["stock.quant"]._update_available_quantity(product, self.loc_stock, qty)
@@ -139,3 +144,50 @@ class TestStockPickingVolume(TransactionCase):
self.picking.button_validate()
self.picking.action_cancel()
self.assertEqual(self.picking.volume, 750)
def test_picking_with_canceled_move(self):
"""
Data:
one picking with two move lines with 5 units of product
Test Case:
set 5 unit of product as available
get the volume of the picking
Expected result:
volume is 5 * 10 * 5 * 3 = 750
The volume is computed from the expected quantity
"""
product2 = self._create_product("Product2", 10.0, 5.0, 3.0)
self._set_product_qty(self.product, 5)
self._set_product_qty(product2, 5)
self.picking.write(
{
"move_ids": [
(
0,
0,
{
"name": product2.name,
"product_id": product2.id,
"product_uom": product2.uom_id.id,
"product_uom_qty": 5.0,
"location_id": self.loc_stock.id,
"location_dest_id": self.loc_customer.id,
},
)
]
}
)
self.picking.action_confirm()
self.picking.action_assign()
self.picking.invalidate_cache()
self.assertEqual(self.picking.volume, 750 * 2)
self.picking.move_ids[1]._action_cancel()
self.picking.invalidate_cache()
self.assertEqual(self.picking.volume, 750)
def test_product_volume(self):
self.assertEqual(self.product._get_volume_for_qty(5), 750)
from_uom = self.env.ref("uom.product_uom_dozen")
self.assertEqual(
self.product._get_volume_for_qty(5 * from_uom.factor, from_uom), 750
)

View File

@@ -1 +1 @@
from . import stock_move
from . import product_product

View File

@@ -1,26 +1,26 @@
# Copyright 2020-2022 Camptocamp SA
# Copyright 2023 ACSONE SA/NV
# Copyright 2023 Michael Tietz (MT Software) <mtietz@mt-software.de>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import models
class StockMove(models.Model):
class ProductProduct(models.Model):
_inherit = "product.product"
_inherit = "stock.move"
def _get_volume_for_qty(self, qty):
def _get_volume_for_qty(self, qty, from_uom=None):
self.ensure_one()
product = self.product_id
if not product.packaging_ids.filtered("volume"):
return super()._get_volume_for_qty(qty=qty)
packagings_with_volume = product.with_context(
if not self.packaging_ids.filtered("volume"):
return super()._get_volume_for_qty(qty, from_uom)
qty = from_uom and from_uom._compute_quantity(qty, self.uom_id) or qty
packagings_with_volume = self.with_context(
_packaging_filter=lambda p: p.volume
).product_qty_by_packaging(qty)
volume = 0
for packaging_info in packagings_with_volume:
if packaging_info.get("is_unit"):
pack_volume = product.volume
pack_volume = self.volume
else:
packaging = self.env["product.packaging"].browse(packaging_info["id"])
pack_volume = packaging.volume

View File

@@ -51,7 +51,7 @@ class TestStockMoveVolume(TransactionCase):
move = self.env["stock.move"].new(
{"product_id": self.product, "product_uom_qty": 16}
)
self.assertEqual(move._get_volume_for_qty(16), 2400)
self.assertEqual(move.product_id._get_volume_for_qty(16), 2400)
def test_move_volume_package_with_dimension(self):
"""
@@ -87,4 +87,4 @@ class TestStockMoveVolume(TransactionCase):
{"product_id": self.product, "product_uom_qty": 16}
)
self.assertEqual(move._get_volume_for_qty(16), 153)
self.assertEqual(move.product_id._get_volume_for_qty(16), 153)