Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[16.0][ADD] shopinvader_restapi_sale_packaging: extracted from shopinvader_sale_packaging #1416

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading