diff --git a/.isort.cfg b/.isort.cfg index a9cf1f5541..9acfc6ffa7 100644 --- a/.isort.cfg +++ b/.isort.cfg @@ -6,4 +6,4 @@ force_grid_wrap=0 combine_as_imports=True use_parentheses=True line_length=79 -known_third_party = StringIO,dateutil,mock,odoo,openupgradelib,psycopg2,requests,setuptools,urllib2,vcr,vcr_unittest,werkzeug +known_third_party = StringIO,cerberus,dateutil,mock,odoo,openupgradelib,psycopg2,requests,setuptools,urllib2,vcr,vcr_unittest,werkzeug diff --git a/shopinvader/services/cart.py b/shopinvader/services/cart.py index 6f2274aca8..3d0edb2ea8 100644 --- a/shopinvader/services/cart.py +++ b/shopinvader/services/cart.py @@ -2,9 +2,9 @@ # Sébastien BEAU # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # pylint: disable=consider-merging-classes-inherited - import logging +from cerberus import Validator from odoo.addons.base_rest.components.service import to_int from odoo.addons.component.core import Component from odoo.exceptions import UserError @@ -66,7 +66,85 @@ def clear(self): cart = self._clear_cart(cart) return self._to_json(cart) + def _get_validator_cart_by_id_domain(self, value): + """ + Get cart by id domain. Limiting to session partner. + :param value: + :return: + """ + return [("partner_id", "=", self.partner.id), ("id", "=", value)] + + def _get_line_copy_vals(self, line): + """ + Prepare copy values to be passed to _add_item + :param line: sale.order.line + :return: dict + """ + return { + "product_id": line.product_id.id, + "item_qty": line.product_uom_qty, + } + + def _get_lines_to_copy(self, cart): + return cart.order_line + + # pylint: disable=W8102,W8106 + def copy(self, **params): + """ + This service allows + :param params: + :return: + """ + return self._copy(**params) + + def _copy(self, **params): + """ + Copy the cart given by id without the lines + They will be re-added + :return: dict/json + """ + cart = self.env["sale.order"].search( + self._get_validator_cart_by_id_domain(params.get("id")) + ) + # Copy the existing cart + # Delete all lines and re-add them with 'shopinvader' flavour + new_cart = cart.copy({"order_line": False, "typology": "cart"}) + for line in self._get_lines_to_copy(cart): + vals = self._get_line_copy_vals(line) + self._add_item(new_cart, vals) + + return self._to_json(new_cart) + # Validator + def _cart_validator_exists(self, field, value, error): + """ + Implements 'check_with' validation + :param field: + :param value: + :param error: + :return: + """ + cart = self.env["sale.order"].search( + self._get_validator_cart_by_id_domain(value) + ) + if len(cart) != 1: + error( + field, _("The cart does not exists or does not belong to you!") + ) + + def _validator_copy(self): + return { + "id": { + "coerce": to_int, + "required": True, + "type": "integer", + "check_with": self._cart_validator_exists, + } + } + + def _validator_return_copy(self): + return Validator({}, allow_unknown=True) + def _validator_search(self): return {} diff --git a/shopinvader/tests/__init__.py b/shopinvader/tests/__init__.py index e52173db7c..20d63745ba 100644 --- a/shopinvader/tests/__init__.py +++ b/shopinvader/tests/__init__.py @@ -1,6 +1,7 @@ from . import test_controller from . import test_backend from . import test_cart +from . import test_cart_copy from . import test_cart_item from . import test_address from . import test_partner_validation diff --git a/shopinvader/tests/test_cart_copy.py b/shopinvader/tests/test_cart_copy.py new file mode 100644 index 0000000000..45f8ac9a23 --- /dev/null +++ b/shopinvader/tests/test_cart_copy.py @@ -0,0 +1,34 @@ +# Copyright 2020 ACSONE SA/NV () +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from odoo.exceptions import UserError + +from .test_cart import CommonConnectedCartCase + + +class TestCartCopy(CommonConnectedCartCase): + @classmethod + def setUpClass(cls): + super(TestCartCopy, cls).setUpClass() + cls.product_copy = cls.env.ref("product.product_product_24") + cls.product_copy.list_price = 500.0 + + def test_cart_copy(self): + # Copy existing cart + # Check if we return a new one with new values + result = self.service.dispatch("copy", params={"id": self.cart.id}) + cart_data = result.get("data") + new_id = cart_data.get("id") + self.assertNotEquals(new_id, self.cart.id) + copy_cart = self.env["sale.order"].browse(new_id) + self.assertEquals("cart", copy_cart.typology) + line = copy_cart.order_line.filtered( + lambda l: l.product_id == self.product_copy + ) + self.assertEquals(500.0, line.price_unit) + + def test_cart_copy_does_not_exist(self): + cart_id = self.cart.id + self.cart.unlink() + # Check validator + with self.assertRaises(UserError): + self.service.dispatch("copy", params={"id": cart_id}) diff --git a/shopinvader_delivery_carrier/services/cart.py b/shopinvader_delivery_carrier/services/cart.py index 88540cbdcd..c7603b942d 100644 --- a/shopinvader_delivery_carrier/services/cart.py +++ b/shopinvader_delivery_carrier/services/cart.py @@ -123,3 +123,12 @@ def _set_carrier(self, cart, carrier_id): def _unset_carrier(self, cart): cart.write({"carrier_id": False}) cart._remove_delivery_line() + + def _get_lines_to_copy(self, cart): + """ + Don't copy delivery lines + :param cart: + :return: + """ + res = super(CartService, self)._get_lines_to_copy(cart) + return res.filtered(lambda l: not l.is_delivery)