Skip to content

Commit

Permalink
[ADD] shopinvader_restapi_sale_packaging: extracted from shopinvader_…
Browse files Browse the repository at this point in the history
…sale_packaging
  • Loading branch information
marielejeune committed Feb 14, 2024
1 parent f833d61 commit 35f91cc
Show file tree
Hide file tree
Showing 31 changed files with 135 additions and 949 deletions.
1 change: 0 additions & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ exclude: |
^shopinvader_sale_automatic_workflow/|
^shopinvader_sale_communication/|
^shopinvader_sale_coupon/|
^shopinvader_sale_packaging/|
^shopinvader_sale_packaging_wishlist/|
^shopinvader_sale_profile/|
^shopinvader_sale_report/|
Expand Down
6 changes: 6 additions & 0 deletions setup/shopinvader_restapi_sale_packaging/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import setuptools

setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)
Empty file.
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
from . import services
from . import models
20 changes: 20 additions & 0 deletions shopinvader_restapi_sale_packaging/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Copyright 2020 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

{
"name": "Shopinvader Restapi Sale Packaging",
"Summary": """
REST services take care of if products are sold by packagings.
""",
"version": "16.0.1.0.0",
"license": "AGPL-3",
"author": "Camptocamp, ACSONE",
"website": "https://github.com/shopinvader/odoo-shopinvader",
"depends": [
"shopinvader_restapi",
"shopinvader_product",
"shopinvader_product_sale_packaging",
"sale_stock",
],
"installable": True,
}
2 changes: 2 additions & 0 deletions shopinvader_restapi_sale_packaging/readme/CONTRIBUTORS.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
* Simone Orsi <[email protected]>
* Marie Lejeune <[email protected]>
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ The development of this module has been financially supported by:

* Camptocamp
* Cosanum
* Acsone
3 changes: 3 additions & 0 deletions shopinvader_restapi_sale_packaging/readme/DESCRIPTION.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Allow to purchase products by packaging.

Available packaging are taken using `stock_packaging_calculator <https://github.com/OCA/stock-logistics-warehouse/tree/16.0/stock_packaging_calculator>`_.
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Copyright 2020 Camptocamp (http://www.camptocamp.com).
# Copyright 2023 Acsone (http://www.acsone.eu).
# @author Simone Orsi <[email protected]>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo.addons.component.core import AbstractComponent
Expand All @@ -18,15 +19,15 @@ def _convert_one_line(self, line):
"packaging_qty": 0.0,
"packaging_by_qty": [],
}
if line.product_packaging:
if line.product_packaging_id:
pkg_vals = line.jsonify(self._parser_line_packaging(), one=True)
res.update(pkg_vals)
return res

def _parser_line_packaging(self):
return [
(
"product_packaging:packaging",
"product_packaging_id:packaging",
lambda rec, fname: self._packaging_to_json(rec[fname]),
),
("product_packaging_qty:packaging_qty"),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Copyright 2020 Camptocamp (http://www.camptocamp.com).
# Copyright 2023 Acsone (http://www.acsone.eu).
# @author Simone Orsi <[email protected]>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo.addons.component.core import Component
Expand All @@ -18,26 +19,26 @@ def _validator_update_item(self):
return res

def _prepare_cart_item(self, params, cart):
# TODO: in theory we should be able to skip prod qty
# since it's computed in `sale_order_line_packaging_qty `
res = super()._prepare_cart_item(params, cart)
res.update(self._packaging_values_from_params(params))
if {"product_packaging_id", "product_packaging_qty"}.issubset(res.keys()):
res.pop("product_uom_qty", None)
return res

def _get_line_copy_vals(self, line):
res = super()._get_line_copy_vals(line)
if line.product_packaging_qty:
res.update(
{
"packaging_id": line.product_packaging.id,
"packaging_id": line.product_packaging_id.id,
"packaging_qty": line.product_packaging_qty,
}
)
return res

def _upgrade_cart_item_quantity_vals(self, item, params, **kw):
res = super()._upgrade_cart_item_quantity_vals(item, params, **kw)
pkg_params = self._packaging_values_from_params(params)
if pkg_params:
res.update(pkg_params)
res.update(self._packaging_values_from_params(params))
if {"product_packaging_id", "product_packaging_qty"}.issubset(res.keys()):
res.pop("product_uom_qty", None)
return res
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Copyright 2020 Camptocamp (http://www.camptocamp.com).
# Copyright 2023 Acsone (http://www.acsone.eu).
# @author Simone Orsi <[email protected]>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

Expand Down Expand Up @@ -39,7 +40,7 @@ def _packaging_values_from_params(self, params):
if "packaging_id" in params and "packaging_qty" in params:
return {
# Make sure packaging_id is wiped if we pass 0
"product_packaging": params.pop("packaging_id") or False,
"product_packaging_id": params.pop("packaging_id") or False,
"product_packaging_qty": params.pop("packaging_qty"),
}
return {}
Expand All @@ -49,8 +50,8 @@ def _packaging_to_json(self, packaging):
return None
return {
"id": packaging.id,
# Use packaging type name because it's translated
"name": packaging.packaging_type_id.name,
"code": packaging.packaging_type_id.code,
# Use packaging level name because it's translated
"name": packaging.packaging_level_id.name,
"code": packaging.packaging_level_id.code,
"barcode": packaging.barcode,
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
from . import test_cart
from . import test_sale
from . import test_product_data
31 changes: 31 additions & 0 deletions shopinvader_restapi_sale_packaging/tests/common.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Copyright 2023 Acsone SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from odoo.tests.common import TransactionCase


class CommonPackagingCase(TransactionCase):
@classmethod
def setUpClass(cls):
super(CommonPackagingCase, cls).setUpClass()
cls.pkg_level_retail_box = cls.env["product.packaging.level"].create(
{
"name": "Retail Box",
"code": "pack",
"sequence": 3,
}
)
cls.pkg_level_transport_box = cls.env["product.packaging.level"].create(
{
"name": "Transport Box",
"code": "case",
"sequence": 4,
}
)
cls.pkg_level_pallet = cls.env["product.packaging.level"].create(
{
"name": "Pallet",
"code": "pallet",
"sequence": 5,
}
)
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
# Copyright 2020 Camptocamp SA
# Simone Orsi <[email protected]>
# Copyright 2023 Acsone SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from odoo.addons.shopinvader.tests.common import CommonCase
from odoo.addons.shopinvader.tests.test_cart_item import ItemCaseMixin
from odoo.addons.shopinvader_restapi.tests.common import CommonCase
from odoo.addons.shopinvader_restapi.tests.test_cart_item import ItemCaseMixin

from .common import CommonPackagingCase

class ConnectedItemCase(ItemCaseMixin, CommonCase):

class ConnectedItemCase(ItemCaseMixin, CommonCase, CommonPackagingCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls._setup_products()
cls.partner = cls.env.ref("shopinvader.partner_1")
cls.cart = cls.env.ref("shopinvader.sale_order_2")
cls.partner = cls.env.ref("shopinvader_restapi.partner_1")
cls.cart = cls.env.ref("shopinvader_restapi.sale_order_2")
# Packages for cls.product_1
cls.pkg_box = cls.env["product.packaging"].create(
{
"name": "Box",
"packaging_level_id": cls.pkg_level_retail_box.id,
"product_id": cls.product_1.id,
"qty": 50,
"barcode": "BOX",
Expand All @@ -24,6 +29,7 @@ def setUpClass(cls):
cls.pkg_big_box = cls.env["product.packaging"].create(
{
"name": "Big Box",
"packaging_level_id": cls.pkg_level_transport_box.id,
"product_id": cls.product_1.id,
"qty": 200,
"barcode": "BIGBOX",
Expand All @@ -32,14 +38,22 @@ def setUpClass(cls):
cls.pkg_pallet = cls.env["product.packaging"].create(
{
"name": "Pallet",
"packaging_level_id": cls.pkg_level_pallet.id,
"product_id": cls.product_1.id,
"qty": 2000,
"barcode": "PALLET",
}
)
# This module adds new keys: recompute
cls._refresh_json_data(
cls, cls.cart.mapped("order_line.product_id") + cls.product_1
# Pallet package for product.product_product_24 (First SOL of cart)
cls.product_2 = cls.env.ref("product.product_product_24")
cls.pkg_pallet_2 = cls.env["product.packaging"].create(
{
"name": "Pallet product 2",
"packaging_level_id": cls.pkg_level_pallet.id,
"product_id": cls.product_2.id,
"qty": 2000,
"barcode": "PALLET 2",
}
)

def setUp(self):
Expand All @@ -53,8 +67,6 @@ def setUp(self):
def test_add_item(self):
self.remove_cart()
last_order = self.env["sale.order"].search([], limit=1, order="id desc")
# TODO: in theory we should be able to skip prod qty
# since it's computed in `sale_order_line_packaging_qty `
cart = self.add_item(
self.product_1.id,
1,
Expand All @@ -67,7 +79,7 @@ def test_add_item(self):
cart_line = cart["lines"]["items"][0]
# check SO line values
line = self.env["sale.order.line"].browse(cart_line["id"])
self.assertEqual(line.product_packaging, self.pkg_pallet)
self.assertEqual(line.product_packaging_id, self.pkg_pallet)
self.assertEqual(line.product_packaging_qty, 2.0)
self.assertEqual(line.product_uom_qty, 4000)
# Check cart line values
Expand All @@ -76,22 +88,23 @@ def test_add_item(self):
cart_line["packaging"],
{
"id": self.pkg_pallet.id,
"name": self.pkg_pallet.packaging_type_id.name,
"code": self.pkg_pallet.packaging_type_id.code,
"name": self.pkg_pallet.packaging_level_id.name,
"code": self.pkg_pallet.packaging_level_id.code,
"barcode": self.pkg_pallet.barcode,
},
)
self.assertEqual(cart_line["packaging_qty"], 2)
self.assertIn("sell_only_by_packaging", cart_line["product"])

def test_update_item(self):
line = self.cart.order_line[0]
line = self.cart.order_line.filtered(
lambda sol: sol.product_id == self.product_2
)
product = line.product_id
cart = self.update_item(
line.id, 1, packaging_id=self.pkg_pallet, packaging_qty=3.0
line.id, 1, packaging_id=self.pkg_pallet_2, packaging_qty=3.0
)
# check SO line values
self.assertEqual(line.product_packaging, self.pkg_pallet)
self.assertEqual(line.product_packaging_id, self.pkg_pallet_2)
self.assertEqual(line.product_packaging_qty, 3.0)
self.assertEqual(line.product_uom_qty, 6000)
# Check cart line values
Expand All @@ -100,21 +113,22 @@ def test_update_item(self):
self.assertEqual(
cart_line["packaging"],
{
"id": self.pkg_pallet.id,
"name": self.pkg_pallet.packaging_type_id.name,
"code": self.pkg_pallet.packaging_type_id.code,
"barcode": self.pkg_pallet.barcode,
"id": self.pkg_pallet_2.id,
"name": self.pkg_pallet_2.packaging_level_id.name,
"code": self.pkg_pallet_2.packaging_level_id.code,
"barcode": self.pkg_pallet_2.barcode,
},
)
self.assertEqual(cart_line["packaging_qty"], 3.0)
self.assertIn("sell_only_by_packaging", cart_line["product"])

def test_copy_line(self):
line = self.cart.order_line[0]
line = self.cart.order_line.filtered(
lambda sol: sol.product_id == self.product_2
)
product = line.product_id
line.write(
{
"product_packaging": self.pkg_pallet.id,
"product_packaging_id": self.pkg_pallet_2.id,
"product_packaging_qty": 4.0,
}
)
Expand All @@ -125,23 +139,20 @@ def test_copy_line(self):
cart_line = [
x for x in cart["lines"]["items"] if x["product"]["id"] == product.id
][0]
self.assertIn("sell_only_by_packaging", cart_line["product"])
self.check_product_and_qty(cart_line, product.id, 8000)
# Check cart line values
self.assertEqual(
cart_line["packaging"],
{
"id": self.pkg_pallet.id,
"name": self.pkg_pallet.packaging_type_id.name,
"code": self.pkg_pallet.packaging_type_id.code,
"barcode": self.pkg_pallet.barcode,
"id": self.pkg_pallet_2.id,
"name": self.pkg_pallet_2.packaging_level_id.name,
"code": self.pkg_pallet_2.packaging_level_id.code,
"barcode": self.pkg_pallet_2.barcode,
},
)
self.assertEqual(cart_line["packaging_qty"], 4.0)
# check SO line values
line = self.env["sale.order.line"].browse(cart_line["id"])
self.assertEqual(line.product_packaging, self.pkg_pallet)
self.assertEqual(line.product_packaging_id, self.pkg_pallet_2)
self.assertEqual(line.product_packaging_qty, 4.0)
self.assertEqual(line.product_uom_qty, 8000)

# TODO: add tests for packaging computation
Loading

0 comments on commit 35f91cc

Please sign in to comment.