Skip to content

Commit

Permalink
s_packaging_calculator: add product_qty_by_packaging_as_str
Browse files Browse the repository at this point in the history
Retrieve quickly packagin bty qty as a string.
  • Loading branch information
simahawk authored and nguyen hoang hiep committed Sep 14, 2021
1 parent 7b7cacc commit 5d44d55
Show file tree
Hide file tree
Showing 5 changed files with 153 additions and 40 deletions.
58 changes: 58 additions & 0 deletions stock_packaging_calculator/models/product.py
@@ -1,6 +1,8 @@
# Copyright 2020 Camptocamp SA
# @author: Simone Orsi <simone.orsi@camptocamp.com>
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl)

import unicodedata
from collections import namedtuple

from odoo import api, models
Expand All @@ -11,6 +13,8 @@
# Unify records as we mix up w/ UoM
Packaging = namedtuple("Packaging", "id name qty barcode is_unit")

NO_BREAK_SPACE_CHAR = unicodedata.lookup("NO-BREAK SPACE")


class Product(models.Model):
_inherit = "product.product"
Expand Down Expand Up @@ -147,3 +151,57 @@ def _prepare_qty_by_packaging_values(self, packaging, qty_per_pkg):
"is_unit": packaging.is_unit,
"barcode": packaging.barcode,
}

def product_qty_by_packaging_as_str(self, prod_qty, include_total_units=False):
"""Return a string representing the qty of each packaging.
:param prod_qty: the qty of current product to translate to pkg qty
:param include_total_units: includes total qty required initially
"""
self.ensure_one()
if not prod_qty:
return ""

qty_by_packaging = self.product_qty_by_packaging(prod_qty)
if not qty_by_packaging:
return ""

# Exclude unit qty and reuse it later
unit_qty = None
has_only_units = True
_qty_by_packaging = []
for pkg_qty in qty_by_packaging:
if pkg_qty["is_unit"]:
unit_qty = pkg_qty["qty"]
continue
has_only_units = False
_qty_by_packaging.append(pkg_qty)
# Browse them all at once
records = self.env["product.packaging"].browse(
[x["id"] for x in _qty_by_packaging]
)
_qty_by_packaging_as_str = self.env.context.get(
"_qty_by_packaging_as_str", self._qty_by_packaging_as_str
)
# Collect all strings representations
as_string = []
for record, info in zip(records, _qty_by_packaging):
bit = _qty_by_packaging_as_str(record, info["qty"])
if bit:
as_string.append(bit)
# Restore unit information if any.
# Skip it if we get only units in the count.
if unit_qty and not has_only_units:
as_string.append(f"{unit_qty} {self.uom_id.name}")
# We want to avoid line break here as this string
# can be used by reports
res = f",{NO_BREAK_SPACE_CHAR}".join(as_string)
if include_total_units and not has_only_units:
res += " " + self._qty_by_packaging_total_units(prod_qty)
return res

def _qty_by_packaging_as_str(self, packaging, qty):
return f"{qty} {packaging.name}"

def _qty_by_packaging_total_units(self, prod_qty):
return f"({prod_qty} {self.uom_id.name})"
1 change: 1 addition & 0 deletions stock_packaging_calculator/tests/__init__.py
@@ -1 +1,2 @@
from . import test_packaging_calc
from . import test_pkg_qty_str
42 changes: 42 additions & 0 deletions stock_packaging_calculator/tests/common.py
@@ -0,0 +1,42 @@
# Copyright 2020 Camptocamp SA
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl)
from odoo.tests import SavepointCase


class TestCommon(SavepointCase):

at_install = False
post_install = True
maxDiff = None

@classmethod
def setUpClass(cls):
super().setUpClass()
cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True))
cls.uom_unit = cls.env.ref("uom.product_uom_unit")
cls.product_a = cls.env["product.product"].create(
{
"name": "Product A",
"uom_id": cls.uom_unit.id,
"uom_po_id": cls.uom_unit.id,
}
)
cls.pkg_box = cls.env["product.packaging"].create(
{"name": "Box", "product_id": cls.product_a.id, "qty": 50, "barcode": "BOX"}
)
cls.pkg_big_box = cls.env["product.packaging"].create(
{
"name": "Big Box",
"product_id": cls.product_a.id,
"qty": 200,
"barcode": "BIGBOX",
}
)
cls.pkg_pallet = cls.env["product.packaging"].create(
{
"name": "Pallet",
"product_id": cls.product_a.id,
"qty": 2000,
"barcode": "PALLET",
}
)
42 changes: 2 additions & 40 deletions stock_packaging_calculator/tests/test_packaging_calc.py
@@ -1,48 +1,10 @@
# Copyright 2020 Camptocamp SA
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl)
from odoo.tests import SavepointCase

from .common import TestCommon
from .utils import make_pkg_values


class TestCalc(SavepointCase):

at_install = False
post_install = True
maxDiff = None

@classmethod
def setUpClass(cls):
super().setUpClass()
cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True))
cls.uom_unit = cls.env.ref("uom.product_uom_unit")
cls.product_a = cls.env["product.product"].create(
{
"name": "Product A",
"uom_id": cls.uom_unit.id,
"uom_po_id": cls.uom_unit.id,
}
)
cls.pkg_box = cls.env["product.packaging"].create(
{"name": "Box", "product_id": cls.product_a.id, "qty": 50, "barcode": "BOX"}
)
cls.pkg_big_box = cls.env["product.packaging"].create(
{
"name": "Big Box",
"product_id": cls.product_a.id,
"qty": 200,
"barcode": "BIGBOX",
}
)
cls.pkg_pallet = cls.env["product.packaging"].create(
{
"name": "Pallet",
"product_id": cls.product_a.id,
"qty": 2000,
"barcode": "PALLET",
}
)

class TestCalc(TestCommon):
def test_contained_mapping(self):
self.assertEqual(
self.product_a.packaging_contained_mapping,
Expand Down
50 changes: 50 additions & 0 deletions stock_packaging_calculator/tests/test_pkg_qty_str.py
@@ -0,0 +1,50 @@
# Copyright 2021 Camptocamp SA
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl)
from .common import TestCommon


class TestAsStr(TestCommon):
def test_as_str(self):
self.assertEqual(self.product_a.product_qty_by_packaging_as_str(10), "")
self.assertEqual(self.product_a.product_qty_by_packaging_as_str(100), "2 Box")
self.assertEqual(
self.product_a.product_qty_by_packaging_as_str(250), "1 Big Box,\xa01 Box"
)
self.assertEqual(
self.product_a.product_qty_by_packaging_as_str(255),
"1 Big Box,\xa01 Box,\xa05 Units",
)

def test_as_str_w_units(self):
self.assertEqual(
self.product_a.product_qty_by_packaging_as_str(
10, include_total_units=True
),
"",
)
self.assertEqual(
self.product_a.product_qty_by_packaging_as_str(
100, include_total_units=True
),
"2 Box (100 Units)",
)
self.assertEqual(
self.product_a.product_qty_by_packaging_as_str(
250, include_total_units=True
),
"1 Big Box,\xa01 Box (250 Units)",
)
self.assertEqual(
self.product_a.product_qty_by_packaging_as_str(
255, include_total_units=True
),
"1 Big Box,\xa01 Box,\xa05 Units (255 Units)",
)

def test_as_str_custom_name(self):
self.assertEqual(
self.product_a.with_context(
_qty_by_packaging_as_str=lambda pkg, qty: f"{pkg.name} {qty} FOO"
).product_qty_by_packaging_as_str(250),
"Big Box 1 FOO,\xa0Box 1 FOO",
)

0 comments on commit 5d44d55

Please sign in to comment.