mirror of
https://github.com/OCA/stock-logistics-warehouse.git
synced 2025-01-21 14:27:28 +02:00
s_packaging_calculator: include barcode
This commit is contained in:
@@ -9,7 +9,7 @@ from odoo.tools import float_compare
|
|||||||
from odoo.addons.base_sparse_field.models.fields import Serialized
|
from odoo.addons.base_sparse_field.models.fields import Serialized
|
||||||
|
|
||||||
# Unify records as we mix up w/ UoM
|
# Unify records as we mix up w/ UoM
|
||||||
Packaging = namedtuple("Packaging", "id name qty is_unit")
|
Packaging = namedtuple("Packaging", "id name qty barcode is_unit")
|
||||||
|
|
||||||
|
|
||||||
class Product(models.Model):
|
class Product(models.Model):
|
||||||
@@ -81,7 +81,7 @@ class Product(models.Model):
|
|||||||
name_getter = self.env.context.get("_packaging_name_getter", lambda x: x.name)
|
name_getter = self.env.context.get("_packaging_name_getter", lambda x: x.name)
|
||||||
packagings = sorted(
|
packagings = sorted(
|
||||||
[
|
[
|
||||||
Packaging(x.id, name_getter(x), x.qty, False)
|
Packaging(x.id, name_getter(x), x.qty, x.barcode, False)
|
||||||
for x in self.packaging_ids.filtered(custom_filter)
|
for x in self.packaging_ids.filtered(custom_filter)
|
||||||
# Exclude the ones w/ zero qty as they are useless for the math
|
# Exclude the ones w/ zero qty as they are useless for the math
|
||||||
if x.qty
|
if x.qty
|
||||||
@@ -94,7 +94,7 @@ class Product(models.Model):
|
|||||||
# NOTE: the ID here could clash w/ one of the packaging's.
|
# NOTE: the ID here could clash w/ one of the packaging's.
|
||||||
# If you create a mapping based on IDs, keep this in mind.
|
# If you create a mapping based on IDs, keep this in mind.
|
||||||
# You can use `is_unit` to check this.
|
# You can use `is_unit` to check this.
|
||||||
Packaging(self.uom_id.id, self.uom_id.name, self.uom_id.factor, True)
|
Packaging(self.uom_id.id, self.uom_id.name, self.uom_id.factor, None, True)
|
||||||
)
|
)
|
||||||
return packagings
|
return packagings
|
||||||
|
|
||||||
@@ -138,4 +138,5 @@ class Product(models.Model):
|
|||||||
"qty": qty_per_pkg,
|
"qty": qty_per_pkg,
|
||||||
"name": packaging.name,
|
"name": packaging.name,
|
||||||
"is_unit": packaging.is_unit,
|
"is_unit": packaging.is_unit,
|
||||||
|
"barcode": packaging.barcode,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,14 @@
|
|||||||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl)
|
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl)
|
||||||
from odoo.tests import SavepointCase
|
from odoo.tests import SavepointCase
|
||||||
|
|
||||||
|
from .utils import make_pkg_values
|
||||||
|
|
||||||
|
|
||||||
class TestCalc(SavepointCase):
|
class TestCalc(SavepointCase):
|
||||||
|
|
||||||
at_install = False
|
at_install = False
|
||||||
post_install = True
|
post_install = True
|
||||||
|
maxDiff = None
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpClass(cls):
|
def setUpClass(cls):
|
||||||
@@ -21,43 +24,32 @@ class TestCalc(SavepointCase):
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
cls.pkg_box = cls.env["product.packaging"].create(
|
cls.pkg_box = cls.env["product.packaging"].create(
|
||||||
{"name": "Box", "product_id": cls.product_a.id, "qty": 50}
|
{"name": "Box", "product_id": cls.product_a.id, "qty": 50, "barcode": "BOX"}
|
||||||
)
|
)
|
||||||
cls.pkg_big_box = cls.env["product.packaging"].create(
|
cls.pkg_big_box = cls.env["product.packaging"].create(
|
||||||
{"name": "Big Box", "product_id": cls.product_a.id, "qty": 200}
|
{
|
||||||
|
"name": "Big Box",
|
||||||
|
"product_id": cls.product_a.id,
|
||||||
|
"qty": 200,
|
||||||
|
"barcode": "BIGBOX",
|
||||||
|
}
|
||||||
)
|
)
|
||||||
cls.pkg_pallet = cls.env["product.packaging"].create(
|
cls.pkg_pallet = cls.env["product.packaging"].create(
|
||||||
{"name": "Pallet", "product_id": cls.product_a.id, "qty": 2000}
|
{
|
||||||
|
"name": "Pallet",
|
||||||
|
"product_id": cls.product_a.id,
|
||||||
|
"qty": 2000,
|
||||||
|
"barcode": "PALLET",
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_contained_mapping(self):
|
def test_contained_mapping(self):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.product_a.packaging_contained_mapping,
|
self.product_a.packaging_contained_mapping,
|
||||||
{
|
{
|
||||||
str(self.pkg_pallet.id): [
|
str(self.pkg_pallet.id): [make_pkg_values(self.pkg_big_box, qty=10)],
|
||||||
{
|
str(self.pkg_big_box.id): [make_pkg_values(self.pkg_box, qty=4)],
|
||||||
"id": self.pkg_big_box.id,
|
str(self.pkg_box.id): [make_pkg_values(self.uom_unit, qty=50)],
|
||||||
"qty": 10,
|
|
||||||
"name": self.pkg_big_box.name,
|
|
||||||
"is_unit": False,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
str(self.pkg_big_box.id): [
|
|
||||||
{
|
|
||||||
"id": self.pkg_box.id,
|
|
||||||
"qty": 4,
|
|
||||||
"name": self.pkg_box.name,
|
|
||||||
"is_unit": False,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
str(self.pkg_box.id): [
|
|
||||||
{
|
|
||||||
"id": self.uom_unit.id,
|
|
||||||
"qty": 50,
|
|
||||||
"name": self.uom_unit.name,
|
|
||||||
"is_unit": True,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
# Update pkg qty
|
# Update pkg qty
|
||||||
@@ -65,132 +57,51 @@ class TestCalc(SavepointCase):
|
|||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.product_a.packaging_contained_mapping,
|
self.product_a.packaging_contained_mapping,
|
||||||
{
|
{
|
||||||
str(self.pkg_pallet.id): [
|
str(self.pkg_pallet.id): [make_pkg_values(self.pkg_big_box, qty=20)],
|
||||||
{
|
str(self.pkg_big_box.id): [make_pkg_values(self.pkg_box, qty=4)],
|
||||||
"id": self.pkg_big_box.id,
|
str(self.pkg_box.id): [make_pkg_values(self.uom_unit, qty=50)],
|
||||||
"qty": 20,
|
|
||||||
"name": self.pkg_big_box.name,
|
|
||||||
"is_unit": False,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
str(self.pkg_big_box.id): [
|
|
||||||
{
|
|
||||||
"id": self.pkg_box.id,
|
|
||||||
"qty": 4,
|
|
||||||
"name": self.pkg_box.name,
|
|
||||||
"is_unit": False,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
str(self.pkg_box.id): [
|
|
||||||
{
|
|
||||||
"id": self.uom_unit.id,
|
|
||||||
"qty": 50,
|
|
||||||
"name": self.uom_unit.name,
|
|
||||||
"is_unit": True,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_calc_1(self):
|
def test_calc_1(self):
|
||||||
"""Test easy behavior 1."""
|
"""Test easy behavior 1."""
|
||||||
expected = [
|
expected = [
|
||||||
{
|
make_pkg_values(self.pkg_pallet, qty=1),
|
||||||
"id": self.pkg_pallet.id,
|
make_pkg_values(self.pkg_big_box, qty=3),
|
||||||
"qty": 1,
|
make_pkg_values(self.pkg_box, qty=1),
|
||||||
"name": self.pkg_pallet.name,
|
make_pkg_values(self.uom_unit, qty=5),
|
||||||
"is_unit": False,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": self.pkg_big_box.id,
|
|
||||||
"qty": 3,
|
|
||||||
"name": self.pkg_big_box.name,
|
|
||||||
"is_unit": False,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": self.pkg_box.id,
|
|
||||||
"qty": 1,
|
|
||||||
"name": self.pkg_box.name,
|
|
||||||
"is_unit": False,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": self.uom_unit.id,
|
|
||||||
"qty": 5,
|
|
||||||
"name": self.uom_unit.name,
|
|
||||||
"is_unit": True,
|
|
||||||
},
|
|
||||||
]
|
]
|
||||||
self.assertEqual(self.product_a.product_qty_by_packaging(2655), expected)
|
self.assertEqual(self.product_a.product_qty_by_packaging(2655), expected)
|
||||||
|
|
||||||
def test_calc_2(self):
|
def test_calc_2(self):
|
||||||
"""Test easy behavior 2."""
|
"""Test easy behavior 2."""
|
||||||
expected = [
|
expected = [
|
||||||
{
|
make_pkg_values(self.pkg_big_box, qty=1),
|
||||||
"id": self.pkg_big_box.id,
|
make_pkg_values(self.pkg_box, qty=3),
|
||||||
"qty": 1,
|
|
||||||
"name": self.pkg_big_box.name,
|
|
||||||
"is_unit": False,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": self.pkg_box.id,
|
|
||||||
"qty": 3,
|
|
||||||
"name": self.pkg_box.name,
|
|
||||||
"is_unit": False,
|
|
||||||
},
|
|
||||||
]
|
]
|
||||||
self.assertEqual(self.product_a.product_qty_by_packaging(350), expected)
|
self.assertEqual(self.product_a.product_qty_by_packaging(350), expected)
|
||||||
|
|
||||||
def test_calc_3(self):
|
def test_calc_3(self):
|
||||||
"""Test easy behavior 3."""
|
"""Test easy behavior 3."""
|
||||||
expected = [
|
expected = [
|
||||||
{
|
make_pkg_values(self.pkg_box, qty=1),
|
||||||
"id": self.pkg_box.id,
|
make_pkg_values(self.uom_unit, qty=30),
|
||||||
"qty": 1,
|
|
||||||
"name": self.pkg_box.name,
|
|
||||||
"is_unit": False,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": self.uom_unit.id,
|
|
||||||
"qty": 30,
|
|
||||||
"name": self.uom_unit.name,
|
|
||||||
"is_unit": True,
|
|
||||||
},
|
|
||||||
]
|
]
|
||||||
self.assertEqual(self.product_a.product_qty_by_packaging(80), expected)
|
self.assertEqual(self.product_a.product_qty_by_packaging(80), expected)
|
||||||
|
|
||||||
def test_calc_6(self):
|
def test_calc_6(self):
|
||||||
"""Test fractional qty is lost."""
|
"""Test fractional qty is lost."""
|
||||||
expected = [
|
expected = [
|
||||||
{
|
make_pkg_values(self.pkg_box, qty=1),
|
||||||
"id": self.pkg_box.id,
|
|
||||||
"qty": 1,
|
|
||||||
"name": self.pkg_box.name,
|
|
||||||
"is_unit": False,
|
|
||||||
},
|
|
||||||
]
|
]
|
||||||
self.assertEqual(self.product_a.product_qty_by_packaging(50.5), expected)
|
self.assertEqual(self.product_a.product_qty_by_packaging(50.5), expected)
|
||||||
|
|
||||||
def test_calc_filter(self):
|
def test_calc_filter(self):
|
||||||
"""Test packaging filter."""
|
"""Test packaging filter."""
|
||||||
expected = [
|
expected = [
|
||||||
{
|
make_pkg_values(self.pkg_big_box, qty=13),
|
||||||
"id": self.pkg_big_box.id,
|
make_pkg_values(self.pkg_box, qty=1),
|
||||||
"qty": 13,
|
make_pkg_values(self.uom_unit, qty=5),
|
||||||
"name": self.pkg_big_box.name,
|
|
||||||
"is_unit": False,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": self.pkg_box.id,
|
|
||||||
"qty": 1,
|
|
||||||
"name": self.pkg_box.name,
|
|
||||||
"is_unit": False,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": self.uom_unit.id,
|
|
||||||
"qty": 5,
|
|
||||||
"name": self.uom_unit.name,
|
|
||||||
"is_unit": True,
|
|
||||||
},
|
|
||||||
]
|
]
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.product_a.with_context(
|
self.product_a.with_context(
|
||||||
@@ -202,30 +113,12 @@ class TestCalc(SavepointCase):
|
|||||||
def test_calc_name_get(self):
|
def test_calc_name_get(self):
|
||||||
"""Test custom name getter."""
|
"""Test custom name getter."""
|
||||||
expected = [
|
expected = [
|
||||||
{
|
make_pkg_values(self.pkg_pallet, qty=1, name="FOO " + self.pkg_pallet.name),
|
||||||
"id": self.pkg_pallet.id,
|
make_pkg_values(
|
||||||
"qty": 1,
|
self.pkg_big_box, qty=3, name="FOO " + self.pkg_big_box.name
|
||||||
"name": "FOO " + self.pkg_pallet.name,
|
),
|
||||||
"is_unit": False,
|
make_pkg_values(self.pkg_box, qty=1, name="FOO " + self.pkg_box.name),
|
||||||
},
|
make_pkg_values(self.uom_unit, qty=5, name=self.uom_unit.name),
|
||||||
{
|
|
||||||
"id": self.pkg_big_box.id,
|
|
||||||
"qty": 3,
|
|
||||||
"name": "FOO " + self.pkg_big_box.name,
|
|
||||||
"is_unit": False,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": self.pkg_box.id,
|
|
||||||
"qty": 1,
|
|
||||||
"name": "FOO " + self.pkg_box.name,
|
|
||||||
"is_unit": False,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": self.uom_unit.id,
|
|
||||||
"qty": 5,
|
|
||||||
"name": self.uom_unit.name,
|
|
||||||
"is_unit": True,
|
|
||||||
},
|
|
||||||
]
|
]
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.product_a.with_context(
|
self.product_a.with_context(
|
||||||
@@ -255,55 +148,20 @@ class TestCalc(SavepointCase):
|
|||||||
def test_calc_sub1(self):
|
def test_calc_sub1(self):
|
||||||
"""Test contained packaging behavior 1."""
|
"""Test contained packaging behavior 1."""
|
||||||
expected = [
|
expected = [
|
||||||
{
|
make_pkg_values(
|
||||||
"id": self.pkg_pallet.id,
|
self.pkg_pallet,
|
||||||
"qty": 1,
|
qty=1,
|
||||||
"name": self.pkg_pallet.name,
|
contained=[make_pkg_values(self.pkg_big_box, qty=10)],
|
||||||
"is_unit": False,
|
),
|
||||||
"contained": [
|
make_pkg_values(
|
||||||
{
|
self.pkg_big_box,
|
||||||
"id": self.pkg_big_box.id,
|
qty=3,
|
||||||
"qty": 10,
|
contained=[make_pkg_values(self.pkg_box, qty=4)],
|
||||||
"name": self.pkg_big_box.name,
|
),
|
||||||
"is_unit": False,
|
make_pkg_values(
|
||||||
},
|
self.pkg_box, qty=1, contained=[make_pkg_values(self.uom_unit, qty=50)],
|
||||||
],
|
),
|
||||||
},
|
make_pkg_values(self.uom_unit, qty=5, contained=None),
|
||||||
{
|
|
||||||
"id": self.pkg_big_box.id,
|
|
||||||
"qty": 3,
|
|
||||||
"name": self.pkg_big_box.name,
|
|
||||||
"is_unit": False,
|
|
||||||
"contained": [
|
|
||||||
{
|
|
||||||
"id": self.pkg_box.id,
|
|
||||||
"qty": 4,
|
|
||||||
"name": self.pkg_box.name,
|
|
||||||
"is_unit": False,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": self.pkg_box.id,
|
|
||||||
"qty": 1,
|
|
||||||
"name": self.pkg_box.name,
|
|
||||||
"is_unit": False,
|
|
||||||
"contained": [
|
|
||||||
{
|
|
||||||
"id": self.uom_unit.id,
|
|
||||||
"qty": 50,
|
|
||||||
"name": self.uom_unit.name,
|
|
||||||
"is_unit": True,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": self.uom_unit.id,
|
|
||||||
"qty": 5,
|
|
||||||
"name": self.uom_unit.name,
|
|
||||||
"is_unit": True,
|
|
||||||
"contained": None,
|
|
||||||
},
|
|
||||||
]
|
]
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.product_a.product_qty_by_packaging(2655, with_contained=True),
|
self.product_a.product_qty_by_packaging(2655, with_contained=True),
|
||||||
@@ -311,64 +169,26 @@ class TestCalc(SavepointCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def test_calc_sub2(self):
|
def test_calc_sub2(self):
|
||||||
"""Test contained packaging behavior 1."""
|
"""Test contained packaging behavior 2."""
|
||||||
self.pkg_box.qty = 30
|
self.pkg_box.qty = 30
|
||||||
expected = [
|
expected = [
|
||||||
{
|
make_pkg_values(
|
||||||
"id": self.pkg_pallet.id,
|
self.pkg_pallet,
|
||||||
"qty": 1,
|
qty=1,
|
||||||
"name": self.pkg_pallet.name,
|
contained=[make_pkg_values(self.pkg_big_box, qty=10)],
|
||||||
"is_unit": False,
|
),
|
||||||
"contained": [
|
make_pkg_values(
|
||||||
{
|
self.pkg_big_box,
|
||||||
"id": self.pkg_big_box.id,
|
qty=3,
|
||||||
"qty": 10,
|
contained=[
|
||||||
"name": self.pkg_big_box.name,
|
make_pkg_values(self.pkg_box, qty=6),
|
||||||
"is_unit": False,
|
make_pkg_values(self.uom_unit, qty=20),
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
),
|
||||||
{
|
make_pkg_values(
|
||||||
"id": self.pkg_big_box.id,
|
self.pkg_box, qty=1, contained=[make_pkg_values(self.uom_unit, qty=30)],
|
||||||
"qty": 3,
|
),
|
||||||
"name": self.pkg_big_box.name,
|
make_pkg_values(self.uom_unit, qty=25, contained=None),
|
||||||
"is_unit": False,
|
|
||||||
"contained": [
|
|
||||||
{
|
|
||||||
"id": self.pkg_box.id,
|
|
||||||
"qty": 6,
|
|
||||||
"name": self.pkg_box.name,
|
|
||||||
"is_unit": False,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": self.uom_unit.id,
|
|
||||||
"qty": 20,
|
|
||||||
"name": self.uom_unit.name,
|
|
||||||
"is_unit": True,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": self.pkg_box.id,
|
|
||||||
"qty": 1,
|
|
||||||
"name": self.pkg_box.name,
|
|
||||||
"is_unit": False,
|
|
||||||
"contained": [
|
|
||||||
{
|
|
||||||
"id": self.uom_unit.id,
|
|
||||||
"qty": 30,
|
|
||||||
"name": self.uom_unit.name,
|
|
||||||
"is_unit": True,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": self.uom_unit.id,
|
|
||||||
"qty": 25,
|
|
||||||
"name": self.uom_unit.name,
|
|
||||||
"is_unit": True,
|
|
||||||
"contained": None,
|
|
||||||
},
|
|
||||||
]
|
]
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.product_a.product_qty_by_packaging(2655, with_contained=True),
|
self.product_a.product_qty_by_packaging(2655, with_contained=True),
|
||||||
|
|||||||
24
stock_packaging_calculator/tests/utils.py
Normal file
24
stock_packaging_calculator/tests/utils.py
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# Copyright 2021 Camptocamp SA
|
||||||
|
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl)
|
||||||
|
|
||||||
|
|
||||||
|
def make_pkg_values(record, **kw):
|
||||||
|
"""Helper to generate test values for packaging.
|
||||||
|
"""
|
||||||
|
if record._name == "uom.uom":
|
||||||
|
is_unit = True
|
||||||
|
barcode = None
|
||||||
|
qty = record.factor
|
||||||
|
elif record._name == "product.packaging":
|
||||||
|
qty = record.qty
|
||||||
|
is_unit = False
|
||||||
|
barcode = record.barcode
|
||||||
|
values = {
|
||||||
|
"id": record.id,
|
||||||
|
"name": record.name,
|
||||||
|
"qty": qty,
|
||||||
|
"barcode": barcode,
|
||||||
|
"is_unit": is_unit,
|
||||||
|
}
|
||||||
|
values.update(kw)
|
||||||
|
return values
|
||||||
Reference in New Issue
Block a user