diff --git a/shopinvader/services/sale.py b/shopinvader/services/sale.py index 89961cef1a..1ed4aeef60 100644 --- a/shopinvader/services/sale.py +++ b/shopinvader/services/sale.py @@ -1,7 +1,9 @@ # Copyright 2017 Akretion (http://www.akretion.com). # @author Sébastien BEAU # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from odoo.exceptions import UserError from odoo.osv import expression +from odoo.tools.translate import _ from odoo.addons.base_rest.components.service import to_int from odoo.addons.component.core import Component @@ -49,6 +51,21 @@ def ask_email_invoice(self, _id): self._ask_email_invoice = True return self.ask_email(_id) + def cancel(self, _id): + order = self._get(_id) + self._cancel(order) + return self._to_json(order)[0] + + def reset_to_cart(self, _id): + order = self._get(_id) + self._cancel(order, reset_to_cart=True) + res = self._to_json(order)[0] + return { + "data": res, + "set_session": {"cart_id": res["id"]}, + "store_cache": {"cart": res}, + } + # Validator def _validator_search(self): default_search_validator = self._default_validator_search() @@ -59,6 +76,12 @@ def _validator_search(self): def _validator_ask_email_invoice(self): return self._validator_ask_email() + def _validator_cancel(self): + return {} + + def _validator_reset_to_cart(self): + return {} + # The following method are 'private' and should be never never NEVER call # from the controller. # All params are trusted as they have been checked before @@ -102,6 +125,18 @@ def _get_invoices(self, sale): domain_state = invoice_service._get_domain_state() return invoices.filtered_domain(domain_state) + def _cancel(self, sale, reset_to_cart=False): + for line in sale.order_line: + if line.qty_delivered > 0 or line.qty_invoiced > 0: + raise UserError( + _("Orders that have been delivered or invoiced cannot be edited.") + ) + sale.action_cancel() + if reset_to_cart: + sale.action_draft() + sale.typology = "cart" + return sale + def _convert_invoices(self, invoices): return [self._convert_one_invoice(invoice) for invoice in invoices] diff --git a/shopinvader/tests/__init__.py b/shopinvader/tests/__init__.py index 086b7fd159..7d0a489385 100644 --- a/shopinvader/tests/__init__.py +++ b/shopinvader/tests/__init__.py @@ -9,6 +9,7 @@ from . import test_product from . import test_product_filter from . import test_sale +from . import test_sale_cancel from . import test_shopinvader_category from . import test_shopinvader_variant_binding_wizard from . import test_shopinvader_category_binding_wizard diff --git a/shopinvader/tests/test_sale.py b/shopinvader/tests/test_sale.py index df568fde21..1fa2df6979 100644 --- a/shopinvader/tests/test_sale.py +++ b/shopinvader/tests/test_sale.py @@ -9,7 +9,7 @@ from .common import CommonCase, CommonTestDownload -class SaleCase(CommonCase, CommonTestDownload): +class CommonSaleCase(CommonCase): @classmethod def setUpClass(cls): super().setUpClass() @@ -25,10 +25,12 @@ def setUpClass(cls): ) def setUp(self, *args, **kwargs): - super(SaleCase, self).setUp(*args, **kwargs) + super().setUp(*args, **kwargs) with self.work_on_services(partner=self.partner) as work: self.service = work.component(usage="sales") + +class SaleCase(CommonSaleCase, CommonTestDownload): def _confirm_and_invoice_sale(self): self.sale.action_confirm() for line in self.sale.order_line: diff --git a/shopinvader/tests/test_sale_cancel.py b/shopinvader/tests/test_sale_cancel.py new file mode 100644 index 0000000000..eb64de07d3 --- /dev/null +++ b/shopinvader/tests/test_sale_cancel.py @@ -0,0 +1,41 @@ +# Copyright 2021 Akretion (https://www.akretion.com). +# @author Pierrick Brun +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo.exceptions import UserError + +from .test_sale import CommonSaleCase + + +class TestSaleCancel(CommonSaleCase): + def test_sale_cancel(self): + self.sale.action_confirm() + self.assertEqual("sale", self.sale.typology) + self.assertEqual("sale", self.sale.state) + + self.service.dispatch("cancel", self.sale.id) + + self.assertEqual("cancel", self.sale.state) + + def test_sale_cancel_fail_if_delivered(self): + self.sale.action_confirm() + # deliver only 1 line + self.sale.order_line[0].write({"qty_delivered": 1}) + self.env["sale.order.line"].flush(records=self.sale.order_line) + with self.assertRaises(UserError): + self.service.dispatch("cancel", self.sale.id) + self.assertEqual("sale", self.sale.typology) + self.assertEqual("sale", self.sale.state) + + def test_sale_cancel_to_cart(self): + self.sale.action_confirm() + self.assertEqual("sale", self.sale.typology) + self.assertEqual("sale", self.sale.state) + + result = self.service.dispatch("reset_to_cart", self.sale.id) + + session = result.get("set_session") + self.assertEqual("draft", self.sale.state) + self.assertEqual("cart", self.sale.typology) + self.assertIsInstance(session, dict) + self.assertEqual(session.get("cart_id"), self.sale.id)