Initial commit: Odoo 18.0-20251222 extra-addons
This commit is contained in:
3
sell_only_by_packaging/tests/__init__.py
Executable file
3
sell_only_by_packaging/tests/__init__.py
Executable file
@@ -0,0 +1,3 @@
|
||||
from . import test_minimum_sellable_qty
|
||||
from . import test_sale_only_by_packaging
|
||||
from . import test_sale_line_onchanges
|
||||
14
sell_only_by_packaging/tests/common.py
Executable file
14
sell_only_by_packaging/tests/common.py
Executable file
@@ -0,0 +1,14 @@
|
||||
# Copyright 2020 Camptocamp SA
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
|
||||
|
||||
from odoo.addons.product_packaging_level_salable.tests.common import Common
|
||||
|
||||
TU_PRODUCT_QTY = 20
|
||||
PL_PRODUCT_QTY = TU_PRODUCT_QTY * 30
|
||||
|
||||
|
||||
class SellOnlyByPackagingCommon(Common):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.env.user.groups_id += cls.env.ref("product.group_stock_packaging")
|
||||
58
sell_only_by_packaging/tests/test_minimum_sellable_qty.py
Executable file
58
sell_only_by_packaging/tests/test_minimum_sellable_qty.py
Executable file
@@ -0,0 +1,58 @@
|
||||
# Copyright 2020 Camptocamp SA
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
|
||||
|
||||
from odoo.tests import TransactionCase
|
||||
|
||||
|
||||
class TestMinimumSellableQty(TransactionCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True))
|
||||
cls.product = cls.env.ref("product.product_product_9")
|
||||
cls.packaging_level_1 = cls.env["product.packaging.level"].create(
|
||||
{"name": "Packaging level 1", "code": "PL1", "sequence": 1}
|
||||
)
|
||||
cls.packaging_level_2 = cls.env["product.packaging.level"].create(
|
||||
{"name": "Packaging level 1", "code": "PL2", "sequence": 2}
|
||||
)
|
||||
cls.packaging_level_3 = cls.env["product.packaging.level"].create(
|
||||
{"name": "Packaging level 3", "code": "PL3", "sequence": 3}
|
||||
)
|
||||
cls.packaging1 = cls.env["product.packaging"].create(
|
||||
{
|
||||
"name": "Packaging of five",
|
||||
"product_id": cls.product.id,
|
||||
"qty": 5.0,
|
||||
"packaging_level_id": cls.packaging_level_1.id,
|
||||
}
|
||||
)
|
||||
cls.packaging2 = cls.env["product.packaging"].create(
|
||||
{
|
||||
"name": "Packing of 3",
|
||||
"product_id": cls.product.id,
|
||||
"qty": 3.0,
|
||||
"packaging_level_id": cls.packaging_level_2.id,
|
||||
}
|
||||
)
|
||||
|
||||
def test_min_sellable_qty(self):
|
||||
"""Check the computation of the minimum sellable quantity."""
|
||||
self.product.product_tmpl_id.sell_only_by_packaging = False
|
||||
self.assertEqual(self.product.min_sellable_qty, 0)
|
||||
self.product.product_tmpl_id.sell_only_by_packaging = True
|
||||
self.assertEqual(self.product.min_sellable_qty, 3)
|
||||
self.assertEqual(self.product.product_tmpl_id.min_sellable_qty, 3)
|
||||
self.packaging2.sales = False
|
||||
self.assertEqual(self.product.min_sellable_qty, 5)
|
||||
self.assertEqual(self.product.product_tmpl_id.min_sellable_qty, 5)
|
||||
self.packaging3 = self.env["product.packaging"].create(
|
||||
{
|
||||
"name": "Packing of 2",
|
||||
"product_id": self.product.id,
|
||||
"qty": 2.0,
|
||||
"packaging_level_id": self.packaging_level_3.id,
|
||||
}
|
||||
)
|
||||
self.assertEqual(self.product.min_sellable_qty, 2)
|
||||
self.assertEqual(self.product.product_tmpl_id.min_sellable_qty, 2)
|
||||
32
sell_only_by_packaging/tests/test_sale_line_onchanges.py
Executable file
32
sell_only_by_packaging/tests/test_sale_line_onchanges.py
Executable file
@@ -0,0 +1,32 @@
|
||||
# Copyright 2020 Camptocamp SA
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
|
||||
import logging
|
||||
|
||||
from odoo.tests import Form
|
||||
|
||||
from odoo.addons.product_packaging_level_salable.tests.common import (
|
||||
PL_PRODUCT_QTY,
|
||||
TU_PRODUCT_QTY,
|
||||
)
|
||||
|
||||
from .common import SellOnlyByPackagingCommon
|
||||
|
||||
|
||||
class TestPackaging(SellOnlyByPackagingCommon):
|
||||
def test_compute_qties(self):
|
||||
with Form(self.order) as so, self.assertLogs(level=logging.WARNING) as logs:
|
||||
with so.order_line.edit(0) as line:
|
||||
line.product_packaging_id = self.packaging_tu
|
||||
line.product_packaging_qty = 31
|
||||
# catch WARNING by _onchange_product_packaging_id
|
||||
self.assertEqual(len(logs.records), 1)
|
||||
self.assertEqual(logs.records[0].levelno, logging.WARNING)
|
||||
# (20*30)+20 = 31*20 = 620
|
||||
expected_qty = TU_PRODUCT_QTY + PL_PRODUCT_QTY
|
||||
self.assertEqual(self.order_line.product_uom_qty, expected_qty)
|
||||
with Form(self.order) as so:
|
||||
with so.order_line.edit(0) as line:
|
||||
line.product_packaging_qty = 30
|
||||
# 20*30 = 600
|
||||
expected_qty = PL_PRODUCT_QTY
|
||||
self.assertEqual(self.order_line.product_uom_qty, expected_qty)
|
||||
113
sell_only_by_packaging/tests/test_sale_only_by_packaging.py
Executable file
113
sell_only_by_packaging/tests/test_sale_only_by_packaging.py
Executable file
@@ -0,0 +1,113 @@
|
||||
# Copyright 2020 Camptocamp SA
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
|
||||
|
||||
import logging
|
||||
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.tests import Form
|
||||
from odoo.tools import mute_logger
|
||||
|
||||
from .common import SellOnlyByPackagingCommon
|
||||
|
||||
|
||||
class TestSaleProductByPackagingOnly(SellOnlyByPackagingCommon):
|
||||
def test_write_auto_fill_packaging(self):
|
||||
order_line = self.order.order_line
|
||||
self.assertFalse(order_line.product_packaging_id)
|
||||
self.assertFalse(order_line.product_packaging_qty)
|
||||
|
||||
order_line.write({"product_uom_qty": 3.0})
|
||||
self.assertFalse(order_line.product_packaging_id)
|
||||
self.assertFalse(order_line.product_packaging_qty)
|
||||
|
||||
self.product.write({"sell_only_by_packaging": True})
|
||||
self.assertFalse(order_line.product_packaging_id)
|
||||
self.assertFalse(order_line.product_packaging_qty)
|
||||
|
||||
order_line.write({"product_uom_qty": self.packaging_tu.qty * 2})
|
||||
self.assertTrue(order_line.product_packaging_id)
|
||||
self.assertTrue(order_line.product_packaging_qty)
|
||||
self.assertEqual(order_line.product_packaging_id, self.packaging_tu)
|
||||
self.assertEqual(order_line.product_packaging_qty, 2)
|
||||
|
||||
with self.assertRaises(ValidationError):
|
||||
order_line.write({"product_packaging_id": False})
|
||||
|
||||
def test_error_sale_packaging(self):
|
||||
# If qty does not match a packaging qty, an exception should be raised
|
||||
self.product.sell_only_by_packaging = True
|
||||
with self.assertRaises(ValidationError):
|
||||
with Form(self.order) as so:
|
||||
with so.order_line.new() as so_line:
|
||||
so_line.product_id = self.product
|
||||
so_line.product_uom_qty = 2
|
||||
|
||||
@mute_logger("odoo.tests.common.onchange")
|
||||
def test_convert_packaging_qty(self):
|
||||
"""
|
||||
Test if the function _convert_packaging_qty is correctly applied
|
||||
during SO line create/edit and if qties are corrects.
|
||||
:return:
|
||||
"""
|
||||
self.product.sell_only_by_packaging = True
|
||||
packaging = self.packaging_tu
|
||||
# For this step, the qty is not forced on the packaging
|
||||
# But the warning will be raise because the value of packaging qty is
|
||||
# not integer package
|
||||
with self.assertRaises(ValidationError):
|
||||
self.order_line.write(
|
||||
{
|
||||
"product_packaging_id": packaging,
|
||||
"product_packaging_qty": 0.6,
|
||||
}
|
||||
)
|
||||
|
||||
# Now force the qty on the packaging
|
||||
packaging.force_sale_qty = True
|
||||
with Form(self.order) as sale_order:
|
||||
with (
|
||||
sale_order.order_line.edit(0) as so_line,
|
||||
self.assertLogs(level=logging.WARNING) as logs,
|
||||
):
|
||||
so_line.product_packaging_id = packaging
|
||||
so_line.product_uom_qty = 52
|
||||
self.assertAlmostEqual(
|
||||
so_line.product_uom_qty, 60, places=self.precision
|
||||
)
|
||||
so_line.product_uom_qty = 40
|
||||
self.assertAlmostEqual(
|
||||
so_line.product_uom_qty, 40, places=self.precision
|
||||
)
|
||||
so_line.product_uom_qty = 38
|
||||
self.assertAlmostEqual(
|
||||
so_line.product_uom_qty, 40, places=self.precision
|
||||
)
|
||||
so_line.product_uom_qty = 22
|
||||
self.assertAlmostEqual(
|
||||
so_line.product_uom_qty, 40, places=self.precision
|
||||
)
|
||||
so_line.product_uom_qty = 72
|
||||
self.assertAlmostEqual(
|
||||
so_line.product_uom_qty, 80, places=self.precision
|
||||
)
|
||||
so_line.product_uom_qty = 209.98
|
||||
self.assertAlmostEqual(
|
||||
so_line.product_uom_qty, 220, places=self.precision
|
||||
)
|
||||
# catch WARNING by _onchange_product_packaging_id
|
||||
self.assertEqual(len(logs.records), 1)
|
||||
self.assertEqual(logs.records[0].levelno, logging.WARNING)
|
||||
|
||||
def test_onchange_qty_is_not_pack_multiple(self):
|
||||
"""Check package when qantity is not a multiple of package quantity.
|
||||
|
||||
When the uom quantity is changed for a value not a multpile of a
|
||||
possible package an error is raised.
|
||||
"""
|
||||
self.product.write({"sell_only_by_packaging": True})
|
||||
self.order_line.product_uom_qty = 40 # 2 packs
|
||||
with self.assertRaises(ValidationError):
|
||||
self.order_line.product_packaging_qty = 0.9
|
||||
self.assertAlmostEqual(
|
||||
self.order_line.product_uom_qty, 18, places=self.precision
|
||||
)
|
||||
Reference in New Issue
Block a user