From 51172a7a7444a3ca39bde67a752b7bee4729ef92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A0n=20Todorovich?= Date: Mon, 23 Aug 2021 13:00:41 -0300 Subject: [PATCH 01/24] [ADD] website_sale_cart_expire Module that allows to automatically cancel carts without activity after a configurable time. --- website_sale_cart_expire/README.rst | 88 ++++ website_sale_cart_expire/__init__.py | 1 + website_sale_cart_expire/__manifest__.py | 16 + website_sale_cart_expire/data/ir_cron.xml | 19 + .../i18n/website_sale_cart_expire.pot | 93 ++++ website_sale_cart_expire/models/__init__.py | 3 + .../models/res_config_settings.py | 13 + website_sale_cart_expire/models/sale_order.py | 27 ++ website_sale_cart_expire/models/website.py | 45 ++ website_sale_cart_expire/readme/CONFIGURE.rst | 1 + .../readme/CONTRIBUTORS.rst | 3 + .../readme/DESCRIPTION.rst | 1 + .../static/description/icon.png | Bin 0 -> 9455 bytes .../static/description/index.html | 432 ++++++++++++++++++ website_sale_cart_expire/tests/__init__.py | 1 + .../tests/test_website_sale_cart_expire.py | 59 +++ .../views/res_config_settings.xml | 54 +++ 17 files changed, 856 insertions(+) create mode 100644 website_sale_cart_expire/README.rst create mode 100644 website_sale_cart_expire/__init__.py create mode 100644 website_sale_cart_expire/__manifest__.py create mode 100644 website_sale_cart_expire/data/ir_cron.xml create mode 100644 website_sale_cart_expire/i18n/website_sale_cart_expire.pot create mode 100644 website_sale_cart_expire/models/__init__.py create mode 100644 website_sale_cart_expire/models/res_config_settings.py create mode 100644 website_sale_cart_expire/models/sale_order.py create mode 100644 website_sale_cart_expire/models/website.py create mode 100644 website_sale_cart_expire/readme/CONFIGURE.rst create mode 100644 website_sale_cart_expire/readme/CONTRIBUTORS.rst create mode 100644 website_sale_cart_expire/readme/DESCRIPTION.rst create mode 100644 website_sale_cart_expire/static/description/icon.png create mode 100644 website_sale_cart_expire/static/description/index.html create mode 100644 website_sale_cart_expire/tests/__init__.py create mode 100644 website_sale_cart_expire/tests/test_website_sale_cart_expire.py create mode 100644 website_sale_cart_expire/views/res_config_settings.xml diff --git a/website_sale_cart_expire/README.rst b/website_sale_cart_expire/README.rst new file mode 100644 index 0000000000..fff544d6be --- /dev/null +++ b/website_sale_cart_expire/README.rst @@ -0,0 +1,88 @@ +======================== +Website Sale Cart Expire +======================== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fe--commerce-lightgray.png?logo=github + :target: https://github.com/OCA/e-commerce/tree/13.0/website_sale_cart_expire + :alt: OCA/e-commerce +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/e-commerce-13-0/e-commerce-13-0-website_sale_cart_expire + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/113/13.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + +Allows to automatically cancel carts without activity after a configurable time. + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +Go to Website > Settings and set a delay for Expire Carts settings. + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Camptocamp + +Contributors +~~~~~~~~~~~~ + +* `Camptocamp `_ + + * Iván Todorovich + +Maintainers +~~~~~~~~~~~ + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +.. |maintainer-ivantodorovich| image:: https://github.com/ivantodorovich.png?size=40px + :target: https://github.com/ivantodorovich + :alt: ivantodorovich + +Current `maintainer `__: + +|maintainer-ivantodorovich| + +This module is part of the `OCA/e-commerce `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/website_sale_cart_expire/__init__.py b/website_sale_cart_expire/__init__.py new file mode 100644 index 0000000000..0650744f6b --- /dev/null +++ b/website_sale_cart_expire/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/website_sale_cart_expire/__manifest__.py b/website_sale_cart_expire/__manifest__.py new file mode 100644 index 0000000000..d5cf809318 --- /dev/null +++ b/website_sale_cart_expire/__manifest__.py @@ -0,0 +1,16 @@ +# Copyright 2021 Camptocamp (http://www.camptocamp.com). +# @author Iván Todorovich +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "Website Sale Cart Expire", + "summary": "Expire abandoned carts", + "version": "13.0.1.0.0", + "author": "Camptocamp, Odoo Community Association (OCA)", + "maintainers": ["ivantodorovich"], + "website": "https://github.com/OCA/e-commerce", + "license": "AGPL-3", + "category": "Website", + "depends": ["website_sale"], + "data": ["data/ir_cron.xml", "views/res_config_settings.xml"], +} diff --git a/website_sale_cart_expire/data/ir_cron.xml b/website_sale_cart_expire/data/ir_cron.xml new file mode 100644 index 0000000000..9cf889b7b5 --- /dev/null +++ b/website_sale_cart_expire/data/ir_cron.xml @@ -0,0 +1,19 @@ + + + + + + Website: Expire Carts + + code + model._scheduler_website_expire_cart() + 5 + minutes + -1 + + + diff --git a/website_sale_cart_expire/i18n/website_sale_cart_expire.pot b/website_sale_cart_expire/i18n/website_sale_cart_expire.pot new file mode 100644 index 0000000000..f2fa8d6ef8 --- /dev/null +++ b/website_sale_cart_expire/i18n/website_sale_cart_expire.pot @@ -0,0 +1,93 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * website_sale_cart_expire +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: website_sale_cart_expire +#: model_terms:ir.ui.view,arch_db:website_sale_cart_expire.res_config_settings_view_form +msgid "" +"Expire Carts\n" +" " +msgstr "" + +#. module: website_sale_cart_expire +#: model_terms:ir.ui.view,arch_db:website_sale_cart_expire.res_config_settings_view_form +msgid "hours" +msgstr "" + +#. module: website_sale_cart_expire +#: model_terms:ir.ui.view,arch_db:website_sale_cart_expire.res_config_settings_view_form +msgid "Automatically cancel carts without activity after a period of time" +msgstr "" + +#. module: website_sale_cart_expire +#: model:ir.model.fields,help:website_sale_cart_expire.field_res_config_settings__cart_expire_delay +#: model:ir.model.fields,help:website_sale_cart_expire.field_website__cart_expire_delay +msgid "" +"Automatically cancel website orders after the given time.\n" +"Set to 0 to disable this feature." +msgstr "" + +#. module: website_sale_cart_expire +#: model:ir.model.fields,field_description:website_sale_cart_expire.field_sale_order__cart_expire_date +msgid "Cart Expire Date" +msgstr "" + +#. module: website_sale_cart_expire +#: code:addons/website_sale_cart_expire/models/website.py:0 +#, python-format +msgid "Cart expired" +msgstr "" + +#. module: website_sale_cart_expire +#: model_terms:ir.ui.view,arch_db:website_sale_cart_expire.res_config_settings_view_form +msgid "Cart is cancelled after" +msgstr "" + +#. module: website_sale_cart_expire +#: model_terms:ir.ui.view,arch_db:website_sale_cart_expire.res_config_settings_view_form +msgid "Carts are cancelled after this delay." +msgstr "" + +#. module: website_sale_cart_expire +#: model:ir.model,name:website_sale_cart_expire.model_res_config_settings +msgid "Config Settings" +msgstr "" + +#. module: website_sale_cart_expire +#: model:ir.model.fields,field_description:website_sale_cart_expire.field_res_config_settings__cart_expire_delay +#: model:ir.model.fields,field_description:website_sale_cart_expire.field_website__cart_expire_delay +msgid "Expire Delay" +msgstr "" + +#. module: website_sale_cart_expire +#: model:ir.model,name:website_sale_cart_expire.model_sale_order +msgid "Sales Order" +msgstr "" + +#. module: website_sale_cart_expire +#: model:ir.model.fields,help:website_sale_cart_expire.field_sale_order__cart_expire_date +msgid "Technical field: The date this cart will automatically expire" +msgstr "" + +#. module: website_sale_cart_expire +#: model:ir.model,name:website_sale_cart_expire.model_website +msgid "Website" +msgstr "" + +#. module: website_sale_cart_expire +#: model:ir.actions.server,name:website_sale_cart_expire.ir_cron_cart_expire_ir_actions_server +#: model:ir.cron,cron_name:website_sale_cart_expire.ir_cron_cart_expire +#: model:ir.cron,name:website_sale_cart_expire.ir_cron_cart_expire +msgid "Website: Expire Carts" +msgstr "" diff --git a/website_sale_cart_expire/models/__init__.py b/website_sale_cart_expire/models/__init__.py new file mode 100644 index 0000000000..5adc056c27 --- /dev/null +++ b/website_sale_cart_expire/models/__init__.py @@ -0,0 +1,3 @@ +from . import sale_order +from . import website +from . import res_config_settings diff --git a/website_sale_cart_expire/models/res_config_settings.py b/website_sale_cart_expire/models/res_config_settings.py new file mode 100644 index 0000000000..72190d947a --- /dev/null +++ b/website_sale_cart_expire/models/res_config_settings.py @@ -0,0 +1,13 @@ +# Copyright 2021 Camptocamp (http://www.camptocamp.com). +# @author Iván Todorovich +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class ResConfigSettings(models.TransientModel): + _inherit = "res.config.settings" + + cart_expire_delay = fields.Float( + related="website_id.cart_expire_delay", readonly=False + ) diff --git a/website_sale_cart_expire/models/sale_order.py b/website_sale_cart_expire/models/sale_order.py new file mode 100644 index 0000000000..674cf9ce96 --- /dev/null +++ b/website_sale_cart_expire/models/sale_order.py @@ -0,0 +1,27 @@ +# Copyright 2021 Camptocamp (http://www.camptocamp.com). +# @author Iván Todorovich +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from datetime import timedelta + +from odoo import api, fields, models + + +class SaleOrder(models.Model): + _inherit = "sale.order" + + cart_expire_date = fields.Datetime( + compute="_compute_cart_expire_date", + help="Technical field: The date this cart will automatically expire", + ) + + @api.depends("write_date", "website_id.cart_expire_delay") + def _compute_cart_expire_date(self): + for rec in self: + if rec.state in ["draft", "sent"] and rec.website_id.cart_expire_delay > 0: + # In case of draft records, use current date + from_date = rec.write_date or fields.Datetime.now() + expire_delta = timedelta(hours=rec.website_id.cart_expire_delay) + rec.cart_expire_date = from_date + expire_delta + elif rec.cart_expire_date: + rec.cart_expire_date = False diff --git a/website_sale_cart_expire/models/website.py b/website_sale_cart_expire/models/website.py new file mode 100644 index 0000000000..63b0764da2 --- /dev/null +++ b/website_sale_cart_expire/models/website.py @@ -0,0 +1,45 @@ +# Copyright 2021 Camptocamp (http://www.camptocamp.com). +# @author Iván Todorovich +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from datetime import timedelta + +from odoo import _, api, fields, models +from odoo.osv import expression + + +class Website(models.Model): + _inherit = "website" + + cart_expire_delay = fields.Float( + string="Expire Delay", + default=0.0, + help="Automatically cancel website orders after the given time.\n" + "Set to 0 to disable this feature.", + ) + + def _get_cart_expire_delay_domain(self): + self.ensure_one() + expire_date = fields.Datetime.now() - timedelta(hours=self.cart_expire_delay) + return [ + ("website_id", "=", self.id), + ("state", "in", ["draft", "sent"]), + ("write_date", "<=", expire_date), + ] + + @api.model + def _scheduler_website_expire_cart(self): + websites = self.search([("cart_expire_delay", ">", 0)]) + if not websites: + return True + # Get all carts to expire + carts_to_expire_domains = [ + website._get_cart_expire_delay_domain() for website in websites + ] + carts_to_expire = self.env["sale.order"].search( + expression.OR(carts_to_expire_domains) + ) + # Expire carts + for cart in carts_to_expire: + cart.message_post(body=_("Cart expired")) + carts_to_expire.action_cancel() diff --git a/website_sale_cart_expire/readme/CONFIGURE.rst b/website_sale_cart_expire/readme/CONFIGURE.rst new file mode 100644 index 0000000000..6780aaa700 --- /dev/null +++ b/website_sale_cart_expire/readme/CONFIGURE.rst @@ -0,0 +1 @@ +Go to Website > Settings and set a delay for Expire Carts settings. diff --git a/website_sale_cart_expire/readme/CONTRIBUTORS.rst b/website_sale_cart_expire/readme/CONTRIBUTORS.rst new file mode 100644 index 0000000000..df7472d000 --- /dev/null +++ b/website_sale_cart_expire/readme/CONTRIBUTORS.rst @@ -0,0 +1,3 @@ +* `Camptocamp `_ + + * Iván Todorovich diff --git a/website_sale_cart_expire/readme/DESCRIPTION.rst b/website_sale_cart_expire/readme/DESCRIPTION.rst new file mode 100644 index 0000000000..dff26ee3d9 --- /dev/null +++ b/website_sale_cart_expire/readme/DESCRIPTION.rst @@ -0,0 +1 @@ +Allows to automatically cancel carts without activity after a configurable time. diff --git a/website_sale_cart_expire/static/description/icon.png b/website_sale_cart_expire/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3a0328b516c4980e8e44cdb63fd945757ddd132d GIT binary patch literal 9455 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 z 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 Xviia!U7SGha1wx#SCgwmn*{w2TRX*I literal 0 HcmV?d00001 diff --git a/website_sale_cart_expire/static/description/index.html b/website_sale_cart_expire/static/description/index.html new file mode 100644 index 0000000000..4d0d63c6e4 --- /dev/null +++ b/website_sale_cart_expire/static/description/index.html @@ -0,0 +1,432 @@ + + + + + + +Website Sale Cart Expire + + + +
+

Website Sale Cart Expire

+ + +

Beta License: AGPL-3 OCA/e-commerce Translate me on Weblate Try me on Runbot

+

Allows to automatically cancel carts without activity after a configurable time.

+

Table of contents

+ +
+

Configuration

+

Go to Website > Settings and set a delay for Expire Carts settings.

+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Camptocamp
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

Current maintainer:

+

ivantodorovich

+

This module is part of the OCA/e-commerce project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/website_sale_cart_expire/tests/__init__.py b/website_sale_cart_expire/tests/__init__.py new file mode 100644 index 0000000000..7043f0665e --- /dev/null +++ b/website_sale_cart_expire/tests/__init__.py @@ -0,0 +1 @@ +from . import test_website_sale_cart_expire diff --git a/website_sale_cart_expire/tests/test_website_sale_cart_expire.py b/website_sale_cart_expire/tests/test_website_sale_cart_expire.py new file mode 100644 index 0000000000..7e385b2030 --- /dev/null +++ b/website_sale_cart_expire/tests/test_website_sale_cart_expire.py @@ -0,0 +1,59 @@ +# Copyright 2021 Camptocamp (http://www.camptocamp.com). +# @author Iván Todorovich +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from datetime import datetime, timedelta + +import mock + +from odoo.tests import common + + +class TestWebsiteSaleCartExpire(common.SavepointCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + # Websites + cls.website_1 = cls.env.ref("website.default_website") + cls.website_2 = cls.env.ref("website.website2") + cls.website_1.cart_expire_delay = 0.00 # hours (= disabled) + cls.website_2.cart_expire_delay = 2.00 # hours + # Orders + cls.order_1 = cls.env.ref("website_sale.website_sale_order_1") + cls.order_2 = cls.env.ref("website_sale.website_sale_order_2") + cls.order_3 = cls.env.ref("website_sale.website_sale_order_3") + cls.order_4 = cls.env.ref("website_sale.website_sale_order_4") + cls.orders = cls.order_1 + cls.order_2 + cls.order_3 + cls.order_4 + # Set to draft and assign all to website_2 + # (this also updates write_date to now()) + cls.orders.write({"state": "draft", "website_id": cls.website_2.id}) + + def test_expire_dates(self): + # Expire Date is set in the future + self.assertTrue(self.order_1.cart_expire_date) + # Changing to a website without expire delay should remove it + self.order_1.website_id = self.website_1 + self.assertFalse(self.order_1.cart_expire_date) + + def test_expire_scheduler(self): + # Case 1: We haven't reached the expire date yet + self.env["website"]._scheduler_website_expire_cart() + for order in self.orders: + self.assertEqual(order.state, "draft") + # Case 2: We have reached website 2 expire date + with mock.patch("odoo.fields.Datetime.now") as mock_now: + mock_now.return_value = datetime.now() + timedelta(hours=3) + self.env["website"]._scheduler_website_expire_cart() + for order in self.orders: + self.assertEqual(order.state, "cancel") + + def test_expire_scheduler_multi_website(self): + # For this test, we split the orders among the 2 websites + (self.order_1 + self.order_2).write({"website_id": self.website_1.id}) + with mock.patch("odoo.fields.Datetime.now") as mock_now: + mock_now.return_value = datetime.now() + timedelta(hours=3) + self.env["website"]._scheduler_website_expire_cart() + self.assertEqual(self.order_1.state, "draft", "No expire delay on website 1") + self.assertEqual(self.order_2.state, "draft", "No expire delay on website 1") + self.assertEqual(self.order_3.state, "cancel", "Should've been cancelled") + self.assertEqual(self.order_4.state, "cancel", "Should've been cancelled") diff --git a/website_sale_cart_expire/views/res_config_settings.xml b/website_sale_cart_expire/views/res_config_settings.xml new file mode 100644 index 0000000000..5919514e7b --- /dev/null +++ b/website_sale_cart_expire/views/res_config_settings.xml @@ -0,0 +1,54 @@ + + + + + res.config.settings + + +
+
+
+
+ Expire Carts + +
+ Automatically cancel carts without activity after a period of time +
+
+
+
+
+
+
+
+
+
+ + + From 90e0aa4ded5c6f662b2cbc216fa8799a5ba8f5b6 Mon Sep 17 00:00:00 2001 From: Ioan Galan Date: Mon, 15 Nov 2021 15:25:07 +0100 Subject: [PATCH 02/24] [MIG] website_sale_cart_expire: Migration to 14.0 --- website_sale_cart_expire/README.rst | 10 ++++---- website_sale_cart_expire/__manifest__.py | 2 +- .../i18n/website_sale_cart_expire.pot | 23 ++++++++++++++++++- .../static/description/index.html | 6 ++--- 4 files changed, 31 insertions(+), 10 deletions(-) diff --git a/website_sale_cart_expire/README.rst b/website_sale_cart_expire/README.rst index fff544d6be..cc4f618264 100644 --- a/website_sale_cart_expire/README.rst +++ b/website_sale_cart_expire/README.rst @@ -14,13 +14,13 @@ Website Sale Cart Expire :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fe--commerce-lightgray.png?logo=github - :target: https://github.com/OCA/e-commerce/tree/13.0/website_sale_cart_expire + :target: https://github.com/OCA/e-commerce/tree/14.0/website_sale_cart_expire :alt: OCA/e-commerce .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png - :target: https://translation.odoo-community.org/projects/e-commerce-13-0/e-commerce-13-0-website_sale_cart_expire + :target: https://translation.odoo-community.org/projects/e-commerce-14-0/e-commerce-14-0-website_sale_cart_expire :alt: Translate me on Weblate .. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png - :target: https://runbot.odoo-community.org/runbot/113/13.0 + :target: https://runbot.odoo-community.org/runbot/113/14.0 :alt: Try me on Runbot |badge1| |badge2| |badge3| |badge4| |badge5| @@ -43,7 +43,7 @@ Bug Tracker Bugs are tracked on `GitHub Issues `_. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us smashing it by providing a detailed and welcomed -`feedback `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -83,6 +83,6 @@ Current `maintainer `__: |maintainer-ivantodorovich| -This module is part of the `OCA/e-commerce `_ project on GitHub. +This module is part of the `OCA/e-commerce `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/website_sale_cart_expire/__manifest__.py b/website_sale_cart_expire/__manifest__.py index d5cf809318..fa3bd4e1fc 100644 --- a/website_sale_cart_expire/__manifest__.py +++ b/website_sale_cart_expire/__manifest__.py @@ -5,7 +5,7 @@ { "name": "Website Sale Cart Expire", "summary": "Expire abandoned carts", - "version": "13.0.1.0.0", + "version": "14.0.1.0.0", "author": "Camptocamp, Odoo Community Association (OCA)", "maintainers": ["ivantodorovich"], "website": "https://github.com/OCA/e-commerce", diff --git a/website_sale_cart_expire/i18n/website_sale_cart_expire.pot b/website_sale_cart_expire/i18n/website_sale_cart_expire.pot index f2fa8d6ef8..024839b5de 100644 --- a/website_sale_cart_expire/i18n/website_sale_cart_expire.pot +++ b/website_sale_cart_expire/i18n/website_sale_cart_expire.pot @@ -4,7 +4,7 @@ # msgid "" msgstr "" -"Project-Id-Version: Odoo Server 13.0\n" +"Project-Id-Version: Odoo Server 14.0\n" "Report-Msgid-Bugs-To: \n" "Last-Translator: \n" "Language-Team: \n" @@ -64,12 +64,33 @@ msgstr "" msgid "Config Settings" msgstr "" +#. module: website_sale_cart_expire +#: model:ir.model.fields,field_description:website_sale_cart_expire.field_res_config_settings__display_name +#: model:ir.model.fields,field_description:website_sale_cart_expire.field_sale_order__display_name +#: model:ir.model.fields,field_description:website_sale_cart_expire.field_website__display_name +msgid "Display Name" +msgstr "" + #. module: website_sale_cart_expire #: model:ir.model.fields,field_description:website_sale_cart_expire.field_res_config_settings__cart_expire_delay #: model:ir.model.fields,field_description:website_sale_cart_expire.field_website__cart_expire_delay msgid "Expire Delay" msgstr "" +#. module: website_sale_cart_expire +#: model:ir.model.fields,field_description:website_sale_cart_expire.field_res_config_settings__id +#: model:ir.model.fields,field_description:website_sale_cart_expire.field_sale_order__id +#: model:ir.model.fields,field_description:website_sale_cart_expire.field_website__id +msgid "ID" +msgstr "" + +#. module: website_sale_cart_expire +#: model:ir.model.fields,field_description:website_sale_cart_expire.field_res_config_settings____last_update +#: model:ir.model.fields,field_description:website_sale_cart_expire.field_sale_order____last_update +#: model:ir.model.fields,field_description:website_sale_cart_expire.field_website____last_update +msgid "Last Modified on" +msgstr "" + #. module: website_sale_cart_expire #: model:ir.model,name:website_sale_cart_expire.model_sale_order msgid "Sales Order" diff --git a/website_sale_cart_expire/static/description/index.html b/website_sale_cart_expire/static/description/index.html index 4d0d63c6e4..d1bea70974 100644 --- a/website_sale_cart_expire/static/description/index.html +++ b/website_sale_cart_expire/static/description/index.html @@ -367,7 +367,7 @@

Website Sale Cart Expire

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> -

Beta License: AGPL-3 OCA/e-commerce Translate me on Weblate Try me on Runbot

+

Beta License: AGPL-3 OCA/e-commerce Translate me on Weblate Try me on Runbot

Allows to automatically cancel carts without activity after a configurable time.

Table of contents

@@ -391,7 +391,7 @@

Bug Tracker

Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us smashing it by providing a detailed and welcomed -feedback.

+feedback.

Do not contact contributors directly about support or help with technical issues.

@@ -423,7 +423,7 @@

Maintainers

promote its widespread use.

Current maintainer:

ivantodorovich

-

This module is part of the OCA/e-commerce project on GitHub.

+

This module is part of the OCA/e-commerce project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

From 095555a2b7e70562fe4e5e5af5fb4a080549393d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A0n=20Todorovich?= Date: Fri, 10 Jun 2022 13:29:47 -0300 Subject: [PATCH 03/24] [MIG] website_sale_cart_expire: Migration to 15.0 --- website_sale_cart_expire/__manifest__.py | 4 ++-- website_sale_cart_expire/data/ir_cron.xml | 22 +++++++++---------- website_sale_cart_expire/models/__init__.py | 2 +- website_sale_cart_expire/models/website.py | 9 +++----- .../tests/test_website_sale_cart_expire.py | 12 +++++----- .../views/res_config_settings.xml | 2 +- 6 files changed, 22 insertions(+), 29 deletions(-) diff --git a/website_sale_cart_expire/__manifest__.py b/website_sale_cart_expire/__manifest__.py index fa3bd4e1fc..072e84ae4f 100644 --- a/website_sale_cart_expire/__manifest__.py +++ b/website_sale_cart_expire/__manifest__.py @@ -4,8 +4,8 @@ { "name": "Website Sale Cart Expire", - "summary": "Expire abandoned carts", - "version": "14.0.1.0.0", + "summary": "Cancel carts without activity after a configurable time", + "version": "15.0.1.0.0", "author": "Camptocamp, Odoo Community Association (OCA)", "maintainers": ["ivantodorovich"], "website": "https://github.com/OCA/e-commerce", diff --git a/website_sale_cart_expire/data/ir_cron.xml b/website_sale_cart_expire/data/ir_cron.xml index 9cf889b7b5..f78506926c 100644 --- a/website_sale_cart_expire/data/ir_cron.xml +++ b/website_sale_cart_expire/data/ir_cron.xml @@ -4,16 +4,14 @@ @author Iván Todorovich License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). --> - - - - Website: Expire Carts - - code - model._scheduler_website_expire_cart() - 5 - minutes - -1 - - + + + Website: Expire Carts + + code + model._scheduler_website_expire_cart() + 5 + minutes + -1 + diff --git a/website_sale_cart_expire/models/__init__.py b/website_sale_cart_expire/models/__init__.py index 5adc056c27..0cf62fc1fa 100644 --- a/website_sale_cart_expire/models/__init__.py +++ b/website_sale_cart_expire/models/__init__.py @@ -1,3 +1,3 @@ +from . import res_config_settings from . import sale_order from . import website -from . import res_config_settings diff --git a/website_sale_cart_expire/models/website.py b/website_sale_cart_expire/models/website.py index 63b0764da2..a5a54a9039 100644 --- a/website_sale_cart_expire/models/website.py +++ b/website_sale_cart_expire/models/website.py @@ -32,14 +32,11 @@ def _scheduler_website_expire_cart(self): websites = self.search([("cart_expire_delay", ">", 0)]) if not websites: return True - # Get all carts to expire - carts_to_expire_domains = [ - website._get_cart_expire_delay_domain() for website in websites - ] carts_to_expire = self.env["sale.order"].search( - expression.OR(carts_to_expire_domains) + expression.OR( + [website._get_cart_expire_delay_domain() for website in websites] + ) ) - # Expire carts for cart in carts_to_expire: cart.message_post(body=_("Cart expired")) carts_to_expire.action_cancel() diff --git a/website_sale_cart_expire/tests/test_website_sale_cart_expire.py b/website_sale_cart_expire/tests/test_website_sale_cart_expire.py index 7e385b2030..4d127b4025 100644 --- a/website_sale_cart_expire/tests/test_website_sale_cart_expire.py +++ b/website_sale_cart_expire/tests/test_website_sale_cart_expire.py @@ -4,12 +4,12 @@ from datetime import datetime, timedelta -import mock +from freezegun import freeze_time -from odoo.tests import common +from odoo.tests import TransactionCase -class TestWebsiteSaleCartExpire(common.SavepointCase): +class TestWebsiteSaleCartExpire(TransactionCase): @classmethod def setUpClass(cls): super().setUpClass() @@ -41,8 +41,7 @@ def test_expire_scheduler(self): for order in self.orders: self.assertEqual(order.state, "draft") # Case 2: We have reached website 2 expire date - with mock.patch("odoo.fields.Datetime.now") as mock_now: - mock_now.return_value = datetime.now() + timedelta(hours=3) + with freeze_time(datetime.now() + timedelta(hours=3)): self.env["website"]._scheduler_website_expire_cart() for order in self.orders: self.assertEqual(order.state, "cancel") @@ -50,8 +49,7 @@ def test_expire_scheduler(self): def test_expire_scheduler_multi_website(self): # For this test, we split the orders among the 2 websites (self.order_1 + self.order_2).write({"website_id": self.website_1.id}) - with mock.patch("odoo.fields.Datetime.now") as mock_now: - mock_now.return_value = datetime.now() + timedelta(hours=3) + with freeze_time(datetime.now() + timedelta(hours=3)): self.env["website"]._scheduler_website_expire_cart() self.assertEqual(self.order_1.state, "draft", "No expire delay on website 1") self.assertEqual(self.order_2.state, "draft", "No expire delay on website 1") diff --git a/website_sale_cart_expire/views/res_config_settings.xml b/website_sale_cart_expire/views/res_config_settings.xml index 5919514e7b..8570634253 100644 --- a/website_sale_cart_expire/views/res_config_settings.xml +++ b/website_sale_cart_expire/views/res_config_settings.xml @@ -42,7 +42,7 @@ name="cart_expire_delay" widget="float_time" /> - hours + hours. From 2f1f2b1bc2876c3216e7e896c0d3f0712edb9425 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A0n=20Todorovich?= Date: Fri, 15 Jul 2022 12:18:55 -0300 Subject: [PATCH 04/24] [FIX] website_sale_cart_expire: Don't cancel sent quotations In a typical website flow, quotations are moved to sent state when a payment by Wire transfer is chosen. In this scenario, the quotation shouldn't be automatically cancelled. It's up to the salesman to determine when a sent quotation is expired, as technically speaking this isn't just a cart anymore. --- website_sale_cart_expire/models/website.py | 2 +- .../tests/test_website_sale_cart_expire.py | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/website_sale_cart_expire/models/website.py b/website_sale_cart_expire/models/website.py index a5a54a9039..8db9211c49 100644 --- a/website_sale_cart_expire/models/website.py +++ b/website_sale_cart_expire/models/website.py @@ -23,7 +23,7 @@ def _get_cart_expire_delay_domain(self): expire_date = fields.Datetime.now() - timedelta(hours=self.cart_expire_delay) return [ ("website_id", "=", self.id), - ("state", "in", ["draft", "sent"]), + ("state", "=", "draft"), ("write_date", "<=", expire_date), ] diff --git a/website_sale_cart_expire/tests/test_website_sale_cart_expire.py b/website_sale_cart_expire/tests/test_website_sale_cart_expire.py index 4d127b4025..2e0af62afc 100644 --- a/website_sale_cart_expire/tests/test_website_sale_cart_expire.py +++ b/website_sale_cart_expire/tests/test_website_sale_cart_expire.py @@ -55,3 +55,14 @@ def test_expire_scheduler_multi_website(self): self.assertEqual(self.order_2.state, "draft", "No expire delay on website 1") self.assertEqual(self.order_3.state, "cancel", "Should've been cancelled") self.assertEqual(self.order_4.state, "cancel", "Should've been cancelled") + + @freeze_time(datetime.now() + timedelta(hours=3)) + def test_expire_scheduler_ignore_sent_quotation(self): + """Test that sent quotations aren't cancelled + + Quotations can be sent manually or automatically when using + wire transfer as payment. They shouldn't be cancelled. + """ + self.order_1.action_quotation_sent() + self.env["website"]._scheduler_website_expire_cart() + self.assertNotEqual(self.order_1.state, "cancel") From 646053962df8dcd069a21f5e4697a3f5becf9829 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A0n=20Todorovich?= Date: Fri, 15 Jul 2022 12:59:46 -0300 Subject: [PATCH 05/24] [FIX] website_sale_cart_expire: Don't cancel carts in payment --- website_sale_cart_expire/models/sale_order.py | 24 ++++++++++- website_sale_cart_expire/models/website.py | 14 ++++-- .../tests/test_website_sale_cart_expire.py | 43 +++++++++++++++++++ 3 files changed, 76 insertions(+), 5 deletions(-) diff --git a/website_sale_cart_expire/models/sale_order.py b/website_sale_cart_expire/models/sale_order.py index 674cf9ce96..3cdf4b53e6 100644 --- a/website_sale_cart_expire/models/sale_order.py +++ b/website_sale_cart_expire/models/sale_order.py @@ -15,12 +15,32 @@ class SaleOrder(models.Model): help="Technical field: The date this cart will automatically expire", ) - @api.depends("write_date", "website_id.cart_expire_delay") + def _should_bypass_cart_expiration(self): + """Hook method to prevent a cart from expiring""" + self.ensure_one() + # We don't want to cancel carts that are already in payment. + return any( + tx.state in ["pending", "authorized", "done"] for tx in self.transaction_ids + ) + + @api.depends( + "write_date", + "website_id.cart_expire_delay", + "transaction_ids.last_state_change", + ) def _compute_cart_expire_date(self): for rec in self: - if rec.state in ["draft", "sent"] and rec.website_id.cart_expire_delay > 0: + if ( + rec.state == "draft" + and rec.website_id.cart_expire_delay + and not rec._should_bypass_cart_expiration() + ): # In case of draft records, use current date from_date = rec.write_date or fields.Datetime.now() + # In case or records with transactions, consider last tx date + if rec.transaction_ids: + last_tx_date = max(rec.transaction_ids.mapped("last_state_change")) + from_date = max(from_date, last_tx_date) expire_delta = timedelta(hours=rec.website_id.cart_expire_delay) rec.cart_expire_date = from_date + expire_delta elif rec.cart_expire_date: diff --git a/website_sale_cart_expire/models/website.py b/website_sale_cart_expire/models/website.py index 8db9211c49..411eef2890 100644 --- a/website_sale_cart_expire/models/website.py +++ b/website_sale_cart_expire/models/website.py @@ -25,6 +25,11 @@ def _get_cart_expire_delay_domain(self): ("website_id", "=", self.id), ("state", "=", "draft"), ("write_date", "<=", expire_date), + # We don't want to cancel carts that are already in payment. + "|", + ("transaction_ids", "=", False), + "!", + ("transaction_ids.state", "in", ["pending", "authorized", "done"]), ] @api.model @@ -32,11 +37,14 @@ def _scheduler_website_expire_cart(self): websites = self.search([("cart_expire_delay", ">", 0)]) if not websites: return True - carts_to_expire = self.env["sale.order"].search( + carts = self.env["sale.order"].search( expression.OR( [website._get_cart_expire_delay_domain() for website in websites] ) ) - for cart in carts_to_expire: + now = fields.Datetime.now() + for cart in carts: + if not cart.cart_expire_date or cart.cart_expire_date > now: + continue cart.message_post(body=_("Cart expired")) - carts_to_expire.action_cancel() + cart.action_cancel() diff --git a/website_sale_cart_expire/tests/test_website_sale_cart_expire.py b/website_sale_cart_expire/tests/test_website_sale_cart_expire.py index 2e0af62afc..fb31891e34 100644 --- a/website_sale_cart_expire/tests/test_website_sale_cart_expire.py +++ b/website_sale_cart_expire/tests/test_website_sale_cart_expire.py @@ -6,6 +6,7 @@ from freezegun import freeze_time +from odoo import fields from odoo.tests import TransactionCase @@ -13,6 +14,7 @@ class TestWebsiteSaleCartExpire(TransactionCase): @classmethod def setUpClass(cls): super().setUpClass() + cls.tx_counter = 0 # Websites cls.website_1 = cls.env.ref("website.default_website") cls.website_2 = cls.env.ref("website.website2") @@ -28,6 +30,21 @@ def setUpClass(cls): # (this also updates write_date to now()) cls.orders.write({"state": "draft", "website_id": cls.website_2.id}) + def _create_payment_transaction(self, order): + self.tx_counter += 1 + acquirer = self.env.ref("payment.payment_acquirer_test") + return self.env["payment.transaction"].create( + { + "acquirer_id": acquirer.id, + "reference": f"{order.name}-{self.tx_counter}", + "amount": order.amount_total, + "currency_id": order.currency_id.id, + "partner_id": order.partner_id.id, + "operation": "online_direct", + "sale_order_ids": [fields.Command.set([order.id])], + } + ) + def test_expire_dates(self): # Expire Date is set in the future self.assertTrue(self.order_1.cart_expire_date) @@ -66,3 +83,29 @@ def test_expire_scheduler_ignore_sent_quotation(self): self.order_1.action_quotation_sent() self.env["website"]._scheduler_website_expire_cart() self.assertNotEqual(self.order_1.state, "cancel") + + @freeze_time(datetime.now() + timedelta(hours=3)) + def test_expire_scheduler_ignore_in_payment(self): + """Carts with a payment transaction in progress shouldn't expire""" + self._create_payment_transaction(self.order_1) + tx_2 = self._create_payment_transaction(self.order_2) + tx_2._set_pending() + tx_3 = self._create_payment_transaction(self.order_3) + tx_3._set_canceled() + tx_4 = self._create_payment_transaction(self.order_4) + tx_4._set_error("Something went wrong") + # Carts with transactions in progress are not canceled + # Even those with 'draft' or 'error' transactions, because + # the timer is reseted whenever a tx state changes. + self.env["website"]._scheduler_website_expire_cart() + self.assertNotEqual(self.order_1.state, "cancel") + self.assertNotEqual(self.order_2.state, "cancel") + self.assertNotEqual(self.order_3.state, "cancel") + self.assertNotEqual(self.order_4.state, "cancel") + # In case of error, another transaction can be initialized + # However for order_1, no more activity was detected, so it's canceled + with freeze_time(datetime.now() + timedelta(hours=3)): + self._create_payment_transaction(self.order_4) + self.env["website"]._scheduler_website_expire_cart() + self.assertEqual(self.order_1.state, "cancel") + self.assertNotEqual(self.order_4.state, "cancel") From 8fbde010e941ce1f7f2c5898a591beddce0f55af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A0n=20Todorovich?= Date: Fri, 15 Jul 2022 14:40:57 -0300 Subject: [PATCH 06/24] [FIX] Use savepoint and autocommit to avoid possible cron crash --- website_sale_cart_expire/__manifest__.py | 2 +- website_sale_cart_expire/data/ir_cron.xml | 2 +- .../migrations/15.0.1.1.0/post-migrate.py | 17 +++++++++++++++++ website_sale_cart_expire/models/website.py | 17 ++++++++++++++--- 4 files changed, 33 insertions(+), 5 deletions(-) create mode 100644 website_sale_cart_expire/migrations/15.0.1.1.0/post-migrate.py diff --git a/website_sale_cart_expire/__manifest__.py b/website_sale_cart_expire/__manifest__.py index 072e84ae4f..8d53475bce 100644 --- a/website_sale_cart_expire/__manifest__.py +++ b/website_sale_cart_expire/__manifest__.py @@ -5,7 +5,7 @@ { "name": "Website Sale Cart Expire", "summary": "Cancel carts without activity after a configurable time", - "version": "15.0.1.0.0", + "version": "15.0.1.1.0", "author": "Camptocamp, Odoo Community Association (OCA)", "maintainers": ["ivantodorovich"], "website": "https://github.com/OCA/e-commerce", diff --git a/website_sale_cart_expire/data/ir_cron.xml b/website_sale_cart_expire/data/ir_cron.xml index f78506926c..582b8f6338 100644 --- a/website_sale_cart_expire/data/ir_cron.xml +++ b/website_sale_cart_expire/data/ir_cron.xml @@ -9,7 +9,7 @@ Website: Expire Carts code - model._scheduler_website_expire_cart() + model._scheduler_website_expire_cart(autocommit=True) 5 minutes -1 diff --git a/website_sale_cart_expire/migrations/15.0.1.1.0/post-migrate.py b/website_sale_cart_expire/migrations/15.0.1.1.0/post-migrate.py new file mode 100644 index 0000000000..cb04ec548c --- /dev/null +++ b/website_sale_cart_expire/migrations/15.0.1.1.0/post-migrate.py @@ -0,0 +1,17 @@ +# Copyright 2022 Camptocamp SA (https://www.camptocamp.com). +# @author Iván Todorovich +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import SUPERUSER_ID, api + + +def migrate(cr, version): + if not version: + return + env = api.Environment(cr, SUPERUSER_ID, {}) + cron = env.ref( + "website_sale_cart_expire.ir_cron_cart_expire", + raise_if_not_found=False, + ) + if cron: + cron.code = "model._scheduler_website_expire_cart(autocommit=True)" diff --git a/website_sale_cart_expire/models/website.py b/website_sale_cart_expire/models/website.py index 411eef2890..14e2fc1bf7 100644 --- a/website_sale_cart_expire/models/website.py +++ b/website_sale_cart_expire/models/website.py @@ -2,11 +2,14 @@ # @author Iván Todorovich # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +import logging from datetime import timedelta from odoo import _, api, fields, models from odoo.osv import expression +_logger = logging.getLogger(__name__) + class Website(models.Model): _inherit = "website" @@ -33,7 +36,7 @@ def _get_cart_expire_delay_domain(self): ] @api.model - def _scheduler_website_expire_cart(self): + def _scheduler_website_expire_cart(self, autocommit=False): websites = self.search([("cart_expire_delay", ">", 0)]) if not websites: return True @@ -46,5 +49,13 @@ def _scheduler_website_expire_cart(self): for cart in carts: if not cart.cart_expire_date or cart.cart_expire_date > now: continue - cart.message_post(body=_("Cart expired")) - cart.action_cancel() + try: + with self.env.cr.savepoint(): + cart.message_post(body=_("Cart expired")) + cart.action_cancel() + except Exception as e: + _logger.exception("Unable to cancel expired cart %s: %s", cart, e) + else: + if autocommit: + self.env.cr.commit() # pylint: disable=invalid-commit + return True From 66114fe75642feffe986d202fd470e3fe5a547ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A0n=20Todorovich?= Date: Fri, 15 Jul 2022 17:16:06 -0300 Subject: [PATCH 07/24] [IMP] website_sale_cart_expire: Display the cart expiration timer on website --- website_sale_cart_expire/README.rst | 13 +- website_sale_cart_expire/__init__.py | 1 + website_sale_cart_expire/__manifest__.py | 11 +- .../controllers/__init__.py | 1 + website_sale_cart_expire/controllers/main.py | 22 ++++ .../i18n/website_sale_cart_expire.pot | 37 ++---- website_sale_cart_expire/readme/CONFIGURE.rst | 3 + .../static/description/index.html | 8 +- .../static/src/js/website_sale_cart_expire.js | 119 ++++++++++++++++++ website_sale_cart_expire/views/templates.xml | 25 ++++ 10 files changed, 202 insertions(+), 38 deletions(-) create mode 100644 website_sale_cart_expire/controllers/__init__.py create mode 100644 website_sale_cart_expire/controllers/main.py create mode 100644 website_sale_cart_expire/static/src/js/website_sale_cart_expire.js create mode 100644 website_sale_cart_expire/views/templates.xml diff --git a/website_sale_cart_expire/README.rst b/website_sale_cart_expire/README.rst index cc4f618264..8a84ecd16f 100644 --- a/website_sale_cart_expire/README.rst +++ b/website_sale_cart_expire/README.rst @@ -14,13 +14,13 @@ Website Sale Cart Expire :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fe--commerce-lightgray.png?logo=github - :target: https://github.com/OCA/e-commerce/tree/14.0/website_sale_cart_expire + :target: https://github.com/OCA/e-commerce/tree/15.0/website_sale_cart_expire :alt: OCA/e-commerce .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png - :target: https://translation.odoo-community.org/projects/e-commerce-14-0/e-commerce-14-0-website_sale_cart_expire + :target: https://translation.odoo-community.org/projects/e-commerce-15-0/e-commerce-15-0-website_sale_cart_expire :alt: Translate me on Weblate .. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png - :target: https://runbot.odoo-community.org/runbot/113/14.0 + :target: https://runbot.odoo-community.org/runbot/113/15.0 :alt: Try me on Runbot |badge1| |badge2| |badge3| |badge4| |badge5| @@ -37,13 +37,16 @@ Configuration Go to Website > Settings and set a delay for Expire Carts settings. +A cart expiration timer can be displayed on the website by enabling the +Cart Expiration Timer setting in the Customize menu. + Bug Tracker =========== Bugs are tracked on `GitHub Issues `_. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us smashing it by providing a detailed and welcomed -`feedback `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -83,6 +86,6 @@ Current `maintainer `__: |maintainer-ivantodorovich| -This module is part of the `OCA/e-commerce `_ project on GitHub. +This module is part of the `OCA/e-commerce `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/website_sale_cart_expire/__init__.py b/website_sale_cart_expire/__init__.py index 0650744f6b..91c5580fed 100644 --- a/website_sale_cart_expire/__init__.py +++ b/website_sale_cart_expire/__init__.py @@ -1 +1,2 @@ +from . import controllers from . import models diff --git a/website_sale_cart_expire/__manifest__.py b/website_sale_cart_expire/__manifest__.py index 8d53475bce..e870716265 100644 --- a/website_sale_cart_expire/__manifest__.py +++ b/website_sale_cart_expire/__manifest__.py @@ -12,5 +12,14 @@ "license": "AGPL-3", "category": "Website", "depends": ["website_sale"], - "data": ["data/ir_cron.xml", "views/res_config_settings.xml"], + "data": [ + "data/ir_cron.xml", + "views/res_config_settings.xml", + "views/templates.xml", + ], + "assets": { + "web.assets_frontend": [ + "website_sale_cart_expire/static/src/js/website_sale_cart_expire.js", + ], + }, } diff --git a/website_sale_cart_expire/controllers/__init__.py b/website_sale_cart_expire/controllers/__init__.py new file mode 100644 index 0000000000..12a7e529b6 --- /dev/null +++ b/website_sale_cart_expire/controllers/__init__.py @@ -0,0 +1 @@ +from . import main diff --git a/website_sale_cart_expire/controllers/main.py b/website_sale_cart_expire/controllers/main.py new file mode 100644 index 0000000000..48c4d594d4 --- /dev/null +++ b/website_sale_cart_expire/controllers/main.py @@ -0,0 +1,22 @@ +# Copyright 2022 Camptocamp SA (https://www.camptocamp.com). +# @author Iván Todorovich +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import http +from odoo.http import request + +from odoo.addons.website_sale.controllers.main import WebsiteSale + + +class WebsiteSaleCartExpire(WebsiteSale): + @http.route( + ["/shop/cart/get_expire_date"], + type="json", + auth="public", + methods=["POST"], + website=True, + csrf=False, + ) + def get_expire_date(self, **kw): + order = request.website.sale_get_order() + return order.cart_expire_date diff --git a/website_sale_cart_expire/i18n/website_sale_cart_expire.pot b/website_sale_cart_expire/i18n/website_sale_cart_expire.pot index 024839b5de..e2f7c43c60 100644 --- a/website_sale_cart_expire/i18n/website_sale_cart_expire.pot +++ b/website_sale_cart_expire/i18n/website_sale_cart_expire.pot @@ -4,7 +4,7 @@ # msgid "" msgstr "" -"Project-Id-Version: Odoo Server 14.0\n" +"Project-Id-Version: Odoo Server 15.0\n" "Report-Msgid-Bugs-To: \n" "Last-Translator: \n" "Language-Team: \n" @@ -21,8 +21,8 @@ msgid "" msgstr "" #. module: website_sale_cart_expire -#: model_terms:ir.ui.view,arch_db:website_sale_cart_expire.res_config_settings_view_form -msgid "hours" +#: model:ir.model,name:website_sale_cart_expire.model_sale_order +msgid "Allowing sale_order_type to work with website_sale." msgstr "" #. module: website_sale_cart_expire @@ -64,38 +64,12 @@ msgstr "" msgid "Config Settings" msgstr "" -#. module: website_sale_cart_expire -#: model:ir.model.fields,field_description:website_sale_cart_expire.field_res_config_settings__display_name -#: model:ir.model.fields,field_description:website_sale_cart_expire.field_sale_order__display_name -#: model:ir.model.fields,field_description:website_sale_cart_expire.field_website__display_name -msgid "Display Name" -msgstr "" - #. module: website_sale_cart_expire #: model:ir.model.fields,field_description:website_sale_cart_expire.field_res_config_settings__cart_expire_delay #: model:ir.model.fields,field_description:website_sale_cart_expire.field_website__cart_expire_delay msgid "Expire Delay" msgstr "" -#. module: website_sale_cart_expire -#: model:ir.model.fields,field_description:website_sale_cart_expire.field_res_config_settings__id -#: model:ir.model.fields,field_description:website_sale_cart_expire.field_sale_order__id -#: model:ir.model.fields,field_description:website_sale_cart_expire.field_website__id -msgid "ID" -msgstr "" - -#. module: website_sale_cart_expire -#: model:ir.model.fields,field_description:website_sale_cart_expire.field_res_config_settings____last_update -#: model:ir.model.fields,field_description:website_sale_cart_expire.field_sale_order____last_update -#: model:ir.model.fields,field_description:website_sale_cart_expire.field_website____last_update -msgid "Last Modified on" -msgstr "" - -#. module: website_sale_cart_expire -#: model:ir.model,name:website_sale_cart_expire.model_sale_order -msgid "Sales Order" -msgstr "" - #. module: website_sale_cart_expire #: model:ir.model.fields,help:website_sale_cart_expire.field_sale_order__cart_expire_date msgid "Technical field: The date this cart will automatically expire" @@ -112,3 +86,8 @@ msgstr "" #: model:ir.cron,name:website_sale_cart_expire.ir_cron_cart_expire msgid "Website: Expire Carts" msgstr "" + +#. module: website_sale_cart_expire +#: model_terms:ir.ui.view,arch_db:website_sale_cart_expire.res_config_settings_view_form +msgid "hours." +msgstr "" diff --git a/website_sale_cart_expire/readme/CONFIGURE.rst b/website_sale_cart_expire/readme/CONFIGURE.rst index 6780aaa700..8a18e47bc3 100644 --- a/website_sale_cart_expire/readme/CONFIGURE.rst +++ b/website_sale_cart_expire/readme/CONFIGURE.rst @@ -1 +1,4 @@ Go to Website > Settings and set a delay for Expire Carts settings. + +A cart expiration timer can be displayed on the website by enabling the +Cart Expiration Timer setting in the Customize menu. diff --git a/website_sale_cart_expire/static/description/index.html b/website_sale_cart_expire/static/description/index.html index d1bea70974..f04acbf7b0 100644 --- a/website_sale_cart_expire/static/description/index.html +++ b/website_sale_cart_expire/static/description/index.html @@ -367,7 +367,7 @@

Website Sale Cart Expire

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> -

Beta License: AGPL-3 OCA/e-commerce Translate me on Weblate Try me on Runbot

+

Beta License: AGPL-3 OCA/e-commerce Translate me on Weblate Try me on Runbot

Allows to automatically cancel carts without activity after a configurable time.

Table of contents

@@ -385,13 +385,15 @@

Website Sale Cart Expire

Configuration

Go to Website > Settings and set a delay for Expire Carts settings.

+

A cart expiration timer can be displayed on the website by enabling the +Cart Expiration Timer setting in the Customize menu.

Bug Tracker

Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us smashing it by providing a detailed and welcomed -feedback.

+feedback.

Do not contact contributors directly about support or help with technical issues.

@@ -423,7 +425,7 @@

Maintainers

promote its widespread use.

Current maintainer:

ivantodorovich

-

This module is part of the OCA/e-commerce project on GitHub.

+

This module is part of the OCA/e-commerce project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

diff --git a/website_sale_cart_expire/static/src/js/website_sale_cart_expire.js b/website_sale_cart_expire/static/src/js/website_sale_cart_expire.js new file mode 100644 index 0000000000..a78b39bffc --- /dev/null +++ b/website_sale_cart_expire/static/src/js/website_sale_cart_expire.js @@ -0,0 +1,119 @@ +odoo.define("website_sale_cart_expire", (require) => { + "use strict"; + + const publicWidget = require("web.public.widget"); + const time = require("web.time"); + + /** + * Cart Expire Timer widget. + * + * Displays a countdown timer for the cart expiration date. + */ + publicWidget.registry.WebsiteSaleCartExpireTimer = publicWidget.Widget.extend({ + selector: ".my_cart_expiration", + + /** + * @override + */ + start: async function () { + await this._super.apply(this, arguments); + this._setExpirationDate(this.$el.data("order-expire-date")); + const remainingMs = this._getRemainingMs(); + if (remainingMs > 0) { + this._renderTimer(remainingMs); + this._startTimer(); + } + // Attempts to hook into the cart quantity widget to update the expiration date + // whenever it changes. + this.$el.siblings(".my_cart_quantity").on( + "DOMSubtreeModified", + _.debounce(() => this._refreshExpirationDate(), 250) + ); + }, + /** + * @override + */ + destroy: function () { + this.$el.remove(); + this._stopTimer(); + return this._super.apply(this, arguments); + }, + /** + * Sets the timer target date. + * + * @param {String|Date} expireDate + */ + _setExpirationDate: function (expireDate) { + if (typeof expireDate === "string") { + expireDate = time.str_to_datetime(expireDate); + } + this.expireDate = expireDate ? moment(expireDate) : false; + }, + /** + * @returns {Number} + */ + _getRemainingMs: function () { + return this.expireDate ? this.expireDate.diff(moment()) : 0; + }, + /** + * Starts the timer. + */ + _startTimer: function () { + this._stopTimer(); + this.timer = setInterval(this._refreshTimer.bind(this), 1000); + }, + /** + * Stops the timer. + */ + _stopTimer: function () { + if (this.timer) { + clearInterval(this.timer); + } + }, + /** + * Refreshes the countdown timer. + * It destroys itself if the countdown reaches 0. + */ + _refreshTimer: function () { + const remainingMs = this._getRemainingMs(); + this._renderTimer(remainingMs); + if (remainingMs <= 0) { + this._stopTimer(); + this._refreshExpirationDate(); + } + }, + /** + * Updates the remaining time on the dom + */ + _renderTimer: function (remainingMs) { + const remainingMsRounded = Math.ceil(remainingMs / 1000) * 1000; + // Don't show the timer if remaining time is less than 1 hour + if (remainingMsRounded >= 3600000) { + return this.$el.hide(); + } + this.$el.show(); + // Format the countdown timer + const remainingStr = moment.utc(remainingMsRounded).format("mm:ss"); + if (remainingStr !== this.$el.text()) { + this.$el.text(remainingStr); + } + }, + /** + * Updates the expiration date by reading from backend + */ + _refreshExpirationDate: async function () { + const expireDate = await this._rpc({route: "/shop/cart/get_expire_date"}); + this._setExpirationDate(expireDate); + const remainingMs = this._getRemainingMs(); + if (remainingMs > 0) { + this._renderTimer(remainingMs); + this._startTimer(); + this.$el.show(); + } else { + this._stopTimer(); + this.$el.hide(); + } + return this.expireDate; + }, + }); +}); diff --git a/website_sale_cart_expire/views/templates.xml b/website_sale_cart_expire/views/templates.xml new file mode 100644 index 0000000000..8ec4d59d73 --- /dev/null +++ b/website_sale_cart_expire/views/templates.xml @@ -0,0 +1,25 @@ + + + + + + + From bdcd6b947f47da508019c223672730df5c642688 Mon Sep 17 00:00:00 2001 From: "A. Hochuli" Date: Mon, 24 Apr 2023 18:54:41 +0200 Subject: [PATCH 08/24] [MIG] website_sale_cart_expire: Migration to 16.0 [Fix] Use new payment.payment_provider_demo for test cases [Fix] Change acquirer_id to provider_id for test cases --- website_sale_cart_expire/README.rst | 10 +++++----- website_sale_cart_expire/__manifest__.py | 2 +- .../i18n/website_sale_cart_expire.pot | 14 +++++++------- .../static/description/index.html | 6 +++--- .../tests/test_website_sale_cart_expire.py | 4 ++-- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/website_sale_cart_expire/README.rst b/website_sale_cart_expire/README.rst index 8a84ecd16f..86f41589bc 100644 --- a/website_sale_cart_expire/README.rst +++ b/website_sale_cart_expire/README.rst @@ -14,13 +14,13 @@ Website Sale Cart Expire :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fe--commerce-lightgray.png?logo=github - :target: https://github.com/OCA/e-commerce/tree/15.0/website_sale_cart_expire + :target: https://github.com/OCA/e-commerce/tree/16.0/website_sale_cart_expire :alt: OCA/e-commerce .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png - :target: https://translation.odoo-community.org/projects/e-commerce-15-0/e-commerce-15-0-website_sale_cart_expire + :target: https://translation.odoo-community.org/projects/e-commerce-16-0/e-commerce-16-0-website_sale_cart_expire :alt: Translate me on Weblate .. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png - :target: https://runbot.odoo-community.org/runbot/113/15.0 + :target: https://runbot.odoo-community.org/runbot/113/16.0 :alt: Try me on Runbot |badge1| |badge2| |badge3| |badge4| |badge5| @@ -46,7 +46,7 @@ Bug Tracker Bugs are tracked on `GitHub Issues `_. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us smashing it by providing a detailed and welcomed -`feedback `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -86,6 +86,6 @@ Current `maintainer `__: |maintainer-ivantodorovich| -This module is part of the `OCA/e-commerce `_ project on GitHub. +This module is part of the `OCA/e-commerce `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/website_sale_cart_expire/__manifest__.py b/website_sale_cart_expire/__manifest__.py index e870716265..5bc5b64239 100644 --- a/website_sale_cart_expire/__manifest__.py +++ b/website_sale_cart_expire/__manifest__.py @@ -5,7 +5,7 @@ { "name": "Website Sale Cart Expire", "summary": "Cancel carts without activity after a configurable time", - "version": "15.0.1.1.0", + "version": "16.0.1.0.0", "author": "Camptocamp, Odoo Community Association (OCA)", "maintainers": ["ivantodorovich"], "website": "https://github.com/OCA/e-commerce", diff --git a/website_sale_cart_expire/i18n/website_sale_cart_expire.pot b/website_sale_cart_expire/i18n/website_sale_cart_expire.pot index e2f7c43c60..0eff313adb 100644 --- a/website_sale_cart_expire/i18n/website_sale_cart_expire.pot +++ b/website_sale_cart_expire/i18n/website_sale_cart_expire.pot @@ -4,7 +4,7 @@ # msgid "" msgstr "" -"Project-Id-Version: Odoo Server 15.0\n" +"Project-Id-Version: Odoo Server 16.0\n" "Report-Msgid-Bugs-To: \n" "Last-Translator: \n" "Language-Team: \n" @@ -20,11 +20,6 @@ msgid "" " " msgstr "" -#. module: website_sale_cart_expire -#: model:ir.model,name:website_sale_cart_expire.model_sale_order -msgid "Allowing sale_order_type to work with website_sale." -msgstr "" - #. module: website_sale_cart_expire #: model_terms:ir.ui.view,arch_db:website_sale_cart_expire.res_config_settings_view_form msgid "Automatically cancel carts without activity after a period of time" @@ -44,6 +39,7 @@ msgid "Cart Expire Date" msgstr "" #. module: website_sale_cart_expire +#. odoo-python #: code:addons/website_sale_cart_expire/models/website.py:0 #, python-format msgid "Cart expired" @@ -70,6 +66,11 @@ msgstr "" msgid "Expire Delay" msgstr "" +#. module: website_sale_cart_expire +#: model:ir.model,name:website_sale_cart_expire.model_sale_order +msgid "Sales Order" +msgstr "" + #. module: website_sale_cart_expire #: model:ir.model.fields,help:website_sale_cart_expire.field_sale_order__cart_expire_date msgid "Technical field: The date this cart will automatically expire" @@ -83,7 +84,6 @@ msgstr "" #. module: website_sale_cart_expire #: model:ir.actions.server,name:website_sale_cart_expire.ir_cron_cart_expire_ir_actions_server #: model:ir.cron,cron_name:website_sale_cart_expire.ir_cron_cart_expire -#: model:ir.cron,name:website_sale_cart_expire.ir_cron_cart_expire msgid "Website: Expire Carts" msgstr "" diff --git a/website_sale_cart_expire/static/description/index.html b/website_sale_cart_expire/static/description/index.html index f04acbf7b0..0afb120093 100644 --- a/website_sale_cart_expire/static/description/index.html +++ b/website_sale_cart_expire/static/description/index.html @@ -367,7 +367,7 @@

Website Sale Cart Expire

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> -

Beta License: AGPL-3 OCA/e-commerce Translate me on Weblate Try me on Runbot

+

Beta License: AGPL-3 OCA/e-commerce Translate me on Weblate Try me on Runbot

Allows to automatically cancel carts without activity after a configurable time.

Table of contents

@@ -393,7 +393,7 @@

Bug Tracker

Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us smashing it by providing a detailed and welcomed -feedback.

+feedback.

Do not contact contributors directly about support or help with technical issues.

@@ -425,7 +425,7 @@

Maintainers

promote its widespread use.

Current maintainer:

ivantodorovich

-

This module is part of the OCA/e-commerce project on GitHub.

+

This module is part of the OCA/e-commerce project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

diff --git a/website_sale_cart_expire/tests/test_website_sale_cart_expire.py b/website_sale_cart_expire/tests/test_website_sale_cart_expire.py index fb31891e34..d50c7fdcf0 100644 --- a/website_sale_cart_expire/tests/test_website_sale_cart_expire.py +++ b/website_sale_cart_expire/tests/test_website_sale_cart_expire.py @@ -32,10 +32,10 @@ def setUpClass(cls): def _create_payment_transaction(self, order): self.tx_counter += 1 - acquirer = self.env.ref("payment.payment_acquirer_test") + provider = self.env.ref("payment.payment_provider_demo") return self.env["payment.transaction"].create( { - "acquirer_id": acquirer.id, + "provider_id": provider.id, "reference": f"{order.name}-{self.tx_counter}", "amount": order.amount_total, "currency_id": order.currency_id.id, From c7fe4c45fbee044e5b418b5c09b659dbf5096254 Mon Sep 17 00:00:00 2001 From: Ivorra78 Date: Thu, 3 Aug 2023 18:10:28 +0000 Subject: [PATCH 09/24] Added translation using Weblate (Spanish) --- website_sale_cart_expire/i18n/es.po | 94 +++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 website_sale_cart_expire/i18n/es.po diff --git a/website_sale_cart_expire/i18n/es.po b/website_sale_cart_expire/i18n/es.po new file mode 100644 index 0000000000..a9bd9e382e --- /dev/null +++ b/website_sale_cart_expire/i18n/es.po @@ -0,0 +1,94 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * website_sale_cart_expire +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#. module: website_sale_cart_expire +#: model_terms:ir.ui.view,arch_db:website_sale_cart_expire.res_config_settings_view_form +msgid "" +"Expire Carts\n" +" " +msgstr "" + +#. module: website_sale_cart_expire +#: model_terms:ir.ui.view,arch_db:website_sale_cart_expire.res_config_settings_view_form +msgid "Automatically cancel carts without activity after a period of time" +msgstr "" + +#. module: website_sale_cart_expire +#: model:ir.model.fields,help:website_sale_cart_expire.field_res_config_settings__cart_expire_delay +#: model:ir.model.fields,help:website_sale_cart_expire.field_website__cart_expire_delay +msgid "" +"Automatically cancel website orders after the given time.\n" +"Set to 0 to disable this feature." +msgstr "" + +#. module: website_sale_cart_expire +#: model:ir.model.fields,field_description:website_sale_cart_expire.field_sale_order__cart_expire_date +msgid "Cart Expire Date" +msgstr "" + +#. module: website_sale_cart_expire +#. odoo-python +#: code:addons/website_sale_cart_expire/models/website.py:0 +#, python-format +msgid "Cart expired" +msgstr "" + +#. module: website_sale_cart_expire +#: model_terms:ir.ui.view,arch_db:website_sale_cart_expire.res_config_settings_view_form +msgid "Cart is cancelled after" +msgstr "" + +#. module: website_sale_cart_expire +#: model_terms:ir.ui.view,arch_db:website_sale_cart_expire.res_config_settings_view_form +msgid "Carts are cancelled after this delay." +msgstr "" + +#. module: website_sale_cart_expire +#: model:ir.model,name:website_sale_cart_expire.model_res_config_settings +msgid "Config Settings" +msgstr "" + +#. module: website_sale_cart_expire +#: model:ir.model.fields,field_description:website_sale_cart_expire.field_res_config_settings__cart_expire_delay +#: model:ir.model.fields,field_description:website_sale_cart_expire.field_website__cart_expire_delay +msgid "Expire Delay" +msgstr "" + +#. module: website_sale_cart_expire +#: model:ir.model,name:website_sale_cart_expire.model_sale_order +msgid "Sales Order" +msgstr "" + +#. module: website_sale_cart_expire +#: model:ir.model.fields,help:website_sale_cart_expire.field_sale_order__cart_expire_date +msgid "Technical field: The date this cart will automatically expire" +msgstr "" + +#. module: website_sale_cart_expire +#: model:ir.model,name:website_sale_cart_expire.model_website +msgid "Website" +msgstr "" + +#. module: website_sale_cart_expire +#: model:ir.actions.server,name:website_sale_cart_expire.ir_cron_cart_expire_ir_actions_server +#: model:ir.cron,cron_name:website_sale_cart_expire.ir_cron_cart_expire +msgid "Website: Expire Carts" +msgstr "" + +#. module: website_sale_cart_expire +#: model_terms:ir.ui.view,arch_db:website_sale_cart_expire.res_config_settings_view_form +msgid "hours." +msgstr "" From f49d823bd69d501117b9a8a9cd7bc732b1095a32 Mon Sep 17 00:00:00 2001 From: Ivorra78 Date: Thu, 3 Aug 2023 18:11:25 +0000 Subject: [PATCH 10/24] Translated using Weblate (Spanish) Currently translated at 100.0% (14 of 14 strings) Translation: e-commerce-16.0/e-commerce-16.0-website_sale_cart_expire Translate-URL: https://translation.odoo-community.org/projects/e-commerce-16-0/e-commerce-16-0-website_sale_cart_expire/es/ --- website_sale_cart_expire/README.rst | 15 ++++--- website_sale_cart_expire/i18n/es.po | 37 +++++++++++------ .../static/description/index.html | 40 ++++++++++--------- 3 files changed, 54 insertions(+), 38 deletions(-) diff --git a/website_sale_cart_expire/README.rst b/website_sale_cart_expire/README.rst index 86f41589bc..854206a586 100644 --- a/website_sale_cart_expire/README.rst +++ b/website_sale_cart_expire/README.rst @@ -2,10 +2,13 @@ Website Sale Cart Expire ======================== -.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:2a3356f020ea8b4b3a30b6a302c5a2f0c723d56b494bcc388ed2430b856b9b41 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png :target: https://odoo-community.org/page/development-status @@ -19,11 +22,11 @@ Website Sale Cart Expire .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png :target: https://translation.odoo-community.org/projects/e-commerce-16-0/e-commerce-16-0-website_sale_cart_expire :alt: Translate me on Weblate -.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png - :target: https://runbot.odoo-community.org/runbot/113/16.0 - :alt: Try me on Runbot +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/e-commerce&target_branch=16.0 + :alt: Try me on Runboat -|badge1| |badge2| |badge3| |badge4| |badge5| +|badge1| |badge2| |badge3| |badge4| |badge5| Allows to automatically cancel carts without activity after a configurable time. @@ -45,7 +48,7 @@ Bug Tracker Bugs are tracked on `GitHub Issues `_. In case of trouble, please check there if your issue has already been reported. -If you spotted it first, help us smashing it by providing a detailed and welcomed +If you spotted it first, help us to smash it by providing a detailed and welcomed `feedback `_. Do not contact contributors directly about support or help with technical issues. diff --git a/website_sale_cart_expire/i18n/es.po b/website_sale_cart_expire/i18n/es.po index a9bd9e382e..ce3f8d07e8 100644 --- a/website_sale_cart_expire/i18n/es.po +++ b/website_sale_cart_expire/i18n/es.po @@ -6,25 +6,34 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 16.0\n" "Report-Msgid-Bugs-To: \n" -"Last-Translator: Automatically generated\n" +"PO-Revision-Date: 2023-08-03 20:09+0000\n" +"Last-Translator: Ivorra78 \n" "Language-Team: none\n" "Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: \n" "Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.17\n" #. module: website_sale_cart_expire #: model_terms:ir.ui.view,arch_db:website_sale_cart_expire.res_config_settings_view_form msgid "" "Expire Carts\n" -" " +" " msgstr "" +"Carro expirado\n" +" " #. module: website_sale_cart_expire #: model_terms:ir.ui.view,arch_db:website_sale_cart_expire.res_config_settings_view_form msgid "Automatically cancel carts without activity after a period of time" msgstr "" +"Cancelar automáticamente carritos sin actividad después de un período de " +"tiempo" #. module: website_sale_cart_expire #: model:ir.model.fields,help:website_sale_cart_expire.field_res_config_settings__cart_expire_delay @@ -33,62 +42,64 @@ msgid "" "Automatically cancel website orders after the given time.\n" "Set to 0 to disable this feature." msgstr "" +"Cancelar automáticamente los pedidos del sitio web después del tiempo dado.\n" +"Establecer en 0 para desactivar esta función." #. module: website_sale_cart_expire #: model:ir.model.fields,field_description:website_sale_cart_expire.field_sale_order__cart_expire_date msgid "Cart Expire Date" -msgstr "" +msgstr "Fecha de caducidad del carro" #. module: website_sale_cart_expire #. odoo-python #: code:addons/website_sale_cart_expire/models/website.py:0 #, python-format msgid "Cart expired" -msgstr "" +msgstr "Carro caducado" #. module: website_sale_cart_expire #: model_terms:ir.ui.view,arch_db:website_sale_cart_expire.res_config_settings_view_form msgid "Cart is cancelled after" -msgstr "" +msgstr "El carro ha sido cancelado después" #. module: website_sale_cart_expire #: model_terms:ir.ui.view,arch_db:website_sale_cart_expire.res_config_settings_view_form msgid "Carts are cancelled after this delay." -msgstr "" +msgstr "Los carros se cancelan después de este plazo." #. module: website_sale_cart_expire #: model:ir.model,name:website_sale_cart_expire.model_res_config_settings msgid "Config Settings" -msgstr "" +msgstr "Ajustes de Configuración" #. module: website_sale_cart_expire #: model:ir.model.fields,field_description:website_sale_cart_expire.field_res_config_settings__cart_expire_delay #: model:ir.model.fields,field_description:website_sale_cart_expire.field_website__cart_expire_delay msgid "Expire Delay" -msgstr "" +msgstr "Expiración retardada" #. module: website_sale_cart_expire #: model:ir.model,name:website_sale_cart_expire.model_sale_order msgid "Sales Order" -msgstr "" +msgstr "Órdenes de venta" #. module: website_sale_cart_expire #: model:ir.model.fields,help:website_sale_cart_expire.field_sale_order__cart_expire_date msgid "Technical field: The date this cart will automatically expire" -msgstr "" +msgstr "Campo técnico: La fecha en que este carro caducará automáticamente" #. module: website_sale_cart_expire #: model:ir.model,name:website_sale_cart_expire.model_website msgid "Website" -msgstr "" +msgstr "Página Web" #. module: website_sale_cart_expire #: model:ir.actions.server,name:website_sale_cart_expire.ir_cron_cart_expire_ir_actions_server #: model:ir.cron,cron_name:website_sale_cart_expire.ir_cron_cart_expire msgid "Website: Expire Carts" -msgstr "" +msgstr "Página web: Carros caducados" #. module: website_sale_cart_expire #: model_terms:ir.ui.view,arch_db:website_sale_cart_expire.res_config_settings_view_form msgid "hours." -msgstr "" +msgstr "horas." diff --git a/website_sale_cart_expire/static/description/index.html b/website_sale_cart_expire/static/description/index.html index 0afb120093..3352817f1b 100644 --- a/website_sale_cart_expire/static/description/index.html +++ b/website_sale_cart_expire/static/description/index.html @@ -1,20 +1,20 @@ - + - + Website Sale Cart Expire -
-

Website Sale Cart Expire

+
+ + +Odoo Community Association + +
+

Website Sale Cart Expire

-

Beta License: AGPL-3 OCA/e-commerce Translate me on Weblate Try me on Runboat

+

Beta License: AGPL-3 OCA/e-commerce Translate me on Weblate Try me on Runboat

Allows to automatically cancel carts without activity after a configurable time.

Table of contents

@@ -386,13 +391,11 @@

Website Sale Cart Expire

-

Configuration

+

Configuration

Go to Website > Settings and set a delay for Expire Carts settings.

-

A cart expiration timer can be displayed on the website by enabling the -Cart Expiration Timer setting in the Customize menu.

-

Bug Tracker

+

Bug Tracker

Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed @@ -400,15 +403,15 @@

Bug Tracker

Do not contact contributors directly about support or help with technical issues.

-

Credits

+

Credits

-

Authors

+

Authors

  • Camptocamp
-

Maintainers

+

Maintainers

This module is maintained by the OCA.

Odoo Community Association @@ -435,5 +438,6 @@

Maintainers

+
diff --git a/website_sale_cart_expire/static/src/js/website_sale_cart_expire.js b/website_sale_cart_expire/static/src/js/website_sale_cart_expire.js deleted file mode 100644 index a78b39bffc..0000000000 --- a/website_sale_cart_expire/static/src/js/website_sale_cart_expire.js +++ /dev/null @@ -1,119 +0,0 @@ -odoo.define("website_sale_cart_expire", (require) => { - "use strict"; - - const publicWidget = require("web.public.widget"); - const time = require("web.time"); - - /** - * Cart Expire Timer widget. - * - * Displays a countdown timer for the cart expiration date. - */ - publicWidget.registry.WebsiteSaleCartExpireTimer = publicWidget.Widget.extend({ - selector: ".my_cart_expiration", - - /** - * @override - */ - start: async function () { - await this._super.apply(this, arguments); - this._setExpirationDate(this.$el.data("order-expire-date")); - const remainingMs = this._getRemainingMs(); - if (remainingMs > 0) { - this._renderTimer(remainingMs); - this._startTimer(); - } - // Attempts to hook into the cart quantity widget to update the expiration date - // whenever it changes. - this.$el.siblings(".my_cart_quantity").on( - "DOMSubtreeModified", - _.debounce(() => this._refreshExpirationDate(), 250) - ); - }, - /** - * @override - */ - destroy: function () { - this.$el.remove(); - this._stopTimer(); - return this._super.apply(this, arguments); - }, - /** - * Sets the timer target date. - * - * @param {String|Date} expireDate - */ - _setExpirationDate: function (expireDate) { - if (typeof expireDate === "string") { - expireDate = time.str_to_datetime(expireDate); - } - this.expireDate = expireDate ? moment(expireDate) : false; - }, - /** - * @returns {Number} - */ - _getRemainingMs: function () { - return this.expireDate ? this.expireDate.diff(moment()) : 0; - }, - /** - * Starts the timer. - */ - _startTimer: function () { - this._stopTimer(); - this.timer = setInterval(this._refreshTimer.bind(this), 1000); - }, - /** - * Stops the timer. - */ - _stopTimer: function () { - if (this.timer) { - clearInterval(this.timer); - } - }, - /** - * Refreshes the countdown timer. - * It destroys itself if the countdown reaches 0. - */ - _refreshTimer: function () { - const remainingMs = this._getRemainingMs(); - this._renderTimer(remainingMs); - if (remainingMs <= 0) { - this._stopTimer(); - this._refreshExpirationDate(); - } - }, - /** - * Updates the remaining time on the dom - */ - _renderTimer: function (remainingMs) { - const remainingMsRounded = Math.ceil(remainingMs / 1000) * 1000; - // Don't show the timer if remaining time is less than 1 hour - if (remainingMsRounded >= 3600000) { - return this.$el.hide(); - } - this.$el.show(); - // Format the countdown timer - const remainingStr = moment.utc(remainingMsRounded).format("mm:ss"); - if (remainingStr !== this.$el.text()) { - this.$el.text(remainingStr); - } - }, - /** - * Updates the expiration date by reading from backend - */ - _refreshExpirationDate: async function () { - const expireDate = await this._rpc({route: "/shop/cart/get_expire_date"}); - this._setExpirationDate(expireDate); - const remainingMs = this._getRemainingMs(); - if (remainingMs > 0) { - this._renderTimer(remainingMs); - this._startTimer(); - this.$el.show(); - } else { - this._stopTimer(); - this.$el.hide(); - } - return this.expireDate; - }, - }); -}); diff --git a/website_sale_cart_expire/tests/test_website_sale_cart_expire.py b/website_sale_cart_expire/tests/test_website_sale_cart_expire.py index d50c7fdcf0..a5ec78bc35 100644 --- a/website_sale_cart_expire/tests/test_website_sale_cart_expire.py +++ b/website_sale_cart_expire/tests/test_website_sale_cart_expire.py @@ -7,10 +7,11 @@ from freezegun import freeze_time from odoo import fields -from odoo.tests import TransactionCase +from odoo.addons.base.tests.common import BaseCommon -class TestWebsiteSaleCartExpire(TransactionCase): + +class TestWebsiteSaleCartExpire(BaseCommon): @classmethod def setUpClass(cls): super().setUpClass() @@ -32,7 +33,14 @@ def setUpClass(cls): def _create_payment_transaction(self, order): self.tx_counter += 1 - provider = self.env.ref("payment.payment_provider_demo") + provider = self.env.ref("payment.payment_provider_transfer") + provider.write( + { + "state": "enabled", + "is_published": True, + } + ) + provider._transfer_ensure_pending_msg_is_set() return self.env["payment.transaction"].create( { "provider_id": provider.id, @@ -87,6 +95,8 @@ def test_expire_scheduler_ignore_sent_quotation(self): @freeze_time(datetime.now() + timedelta(hours=3)) def test_expire_scheduler_ignore_in_payment(self): """Carts with a payment transaction in progress shouldn't expire""" + if self.env["ir.module.module"]._get("payment_custom").state != "installed": + self.skipTest("Transfer provider is not installed") self._create_payment_transaction(self.order_1) tx_2 = self._create_payment_transaction(self.order_2) tx_2._set_pending() diff --git a/website_sale_cart_expire/views/res_config_settings.xml b/website_sale_cart_expire/views/res_config_settings.xml index 9a87aca76a..8a7d04e257 100644 --- a/website_sale_cart_expire/views/res_config_settings.xml +++ b/website_sale_cart_expire/views/res_config_settings.xml @@ -9,46 +9,35 @@ res.config.settings -
-
-
-
- Expire Carts - -
- Automatically cancel carts without activity after a period of time -
-
-
-
-
+ + +
-
+ + diff --git a/website_sale_cart_expire/views/templates.xml b/website_sale_cart_expire/views/templates.xml deleted file mode 100644 index 51e54ce6cb..0000000000 --- a/website_sale_cart_expire/views/templates.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - From d6eb76d452542c29bfe270ec69963cbcbd303017 Mon Sep 17 00:00:00 2001 From: eduezerouali-tecnativa Date: Thu, 19 Feb 2026 18:44:42 +0100 Subject: [PATCH 17/24] [FIX] website_sale_cart_expire: fix test payment_method_id --- website_sale_cart_expire/README.rst | 2 +- website_sale_cart_expire/__manifest__.py | 2 +- website_sale_cart_expire/static/description/index.html | 2 +- .../tests/test_website_sale_cart_expire.py | 4 ++++ 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/website_sale_cart_expire/README.rst b/website_sale_cart_expire/README.rst index a999804701..672d54ab6d 100644 --- a/website_sale_cart_expire/README.rst +++ b/website_sale_cart_expire/README.rst @@ -11,7 +11,7 @@ Website Sale Cart Expire !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:7d6bc513cb815182563c39afb1cd731dd1fa888282e62a418bd2acea359c65f9 + !! source digest: sha256:28205d71c6d2fdcccdd83f01fbda5702434747419aff45e4c62775e2f2114b06 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png diff --git a/website_sale_cart_expire/__manifest__.py b/website_sale_cart_expire/__manifest__.py index 8160666089..db5a57c86e 100644 --- a/website_sale_cart_expire/__manifest__.py +++ b/website_sale_cart_expire/__manifest__.py @@ -5,7 +5,7 @@ { "name": "Website Sale Cart Expire", "summary": "Cancel carts without activity after a configurable time", - "version": "18.0.1.0.0", + "version": "18.0.1.0.1", "author": "Camptocamp, Odoo Community Association (OCA)", "maintainers": ["ivantodorovich"], "website": "https://github.com/OCA/e-commerce", diff --git a/website_sale_cart_expire/static/description/index.html b/website_sale_cart_expire/static/description/index.html index 734c50a490..50f1590c5b 100644 --- a/website_sale_cart_expire/static/description/index.html +++ b/website_sale_cart_expire/static/description/index.html @@ -372,7 +372,7 @@

Website Sale Cart Expire

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:7d6bc513cb815182563c39afb1cd731dd1fa888282e62a418bd2acea359c65f9 +!! source digest: sha256:28205d71c6d2fdcccdd83f01fbda5702434747419aff45e4c62775e2f2114b06 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

Beta License: AGPL-3 OCA/e-commerce Translate me on Weblate Try me on Runboat

Allows to automatically cancel carts without activity after a diff --git a/website_sale_cart_expire/tests/test_website_sale_cart_expire.py b/website_sale_cart_expire/tests/test_website_sale_cart_expire.py index a5ec78bc35..b211ee8a92 100644 --- a/website_sale_cart_expire/tests/test_website_sale_cart_expire.py +++ b/website_sale_cart_expire/tests/test_website_sale_cart_expire.py @@ -30,6 +30,9 @@ def setUpClass(cls): # Set to draft and assign all to website_2 # (this also updates write_date to now()) cls.orders.write({"state": "draft", "website_id": cls.website_2.id}) + cls.payment_method = cls.env["payment.method"].create( + {"name": "Test_method", "code": "123"} + ) def _create_payment_transaction(self, order): self.tx_counter += 1 @@ -50,6 +53,7 @@ def _create_payment_transaction(self, order): "partner_id": order.partner_id.id, "operation": "online_direct", "sale_order_ids": [fields.Command.set([order.id])], + "payment_method_id": self.payment_method.id, } ) From 6f7bad372678ccddcbe2a73ebd4d6c457b1fffa2 Mon Sep 17 00:00:00 2001 From: mymage Date: Sat, 21 Feb 2026 10:06:49 +0000 Subject: [PATCH 18/24] Translated using Weblate (Italian) Currently translated at 100.0% (14 of 14 strings) Translation: e-commerce-18.0/e-commerce-18.0-website_sale_cart_expire Translate-URL: https://translation.odoo-community.org/projects/e-commerce-18-0/e-commerce-18-0-website_sale_cart_expire/it/ --- website_sale_cart_expire/i18n/it.po | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/website_sale_cart_expire/i18n/it.po b/website_sale_cart_expire/i18n/it.po index e84ca6391d..d0e052c8cf 100644 --- a/website_sale_cart_expire/i18n/it.po +++ b/website_sale_cart_expire/i18n/it.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 16.0\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2024-05-08 07:46+0000\n" +"PO-Revision-Date: 2026-02-21 12:10+0000\n" "Last-Translator: mymage \n" "Language-Team: none\n" "Language: it\n" @@ -14,7 +14,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: \n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.17\n" +"X-Generator: Weblate 5.15.2\n" #. module: website_sale_cart_expire #: model_terms:ir.ui.view,arch_db:website_sale_cart_expire.res_config_settings_view_form @@ -56,7 +56,7 @@ msgstr "Impostazioni configurazione" #. module: website_sale_cart_expire #: model_terms:ir.ui.view,arch_db:website_sale_cart_expire.res_config_settings_view_form msgid "Expire Carts" -msgstr "" +msgstr "Scadenza carrelli" #. module: website_sale_cart_expire #: model:ir.model.fields,field_description:website_sale_cart_expire.field_res_config_settings__cart_expire_delay @@ -67,7 +67,7 @@ msgstr "Ritardo scadenza" #. module: website_sale_cart_expire #: model_terms:ir.ui.view,arch_db:website_sale_cart_expire.res_config_settings_view_form msgid "Hours." -msgstr "" +msgstr "Ore." #. module: website_sale_cart_expire #: model:ir.model,name:website_sale_cart_expire.model_sale_order @@ -82,7 +82,7 @@ msgstr "Campo tecnico: la data in cui questo carrello scade automaticamente" #. module: website_sale_cart_expire #: model_terms:ir.ui.view,arch_db:website_sale_cart_expire.res_config_settings_view_form msgid "Values set here are website-specific." -msgstr "" +msgstr "I valori impostati qui sono specifici per sito web." #. module: website_sale_cart_expire #: model:ir.model,name:website_sale_cart_expire.model_website From 04147418881f1c4f5b61063d4d001760a79d5082 Mon Sep 17 00:00:00 2001 From: mymage Date: Wed, 25 Feb 2026 07:27:16 +0000 Subject: [PATCH 19/24] Translated using Weblate (Italian) Currently translated at 100.0% (14 of 14 strings) Translation: e-commerce-18.0/e-commerce-18.0-website_sale_cart_expire Translate-URL: https://translation.odoo-community.org/projects/e-commerce-18-0/e-commerce-18-0-website_sale_cart_expire/it/ --- website_sale_cart_expire/i18n/it.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website_sale_cart_expire/i18n/it.po b/website_sale_cart_expire/i18n/it.po index d0e052c8cf..a005ad054a 100644 --- a/website_sale_cart_expire/i18n/it.po +++ b/website_sale_cart_expire/i18n/it.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 16.0\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-02-21 12:10+0000\n" +"PO-Revision-Date: 2026-02-25 07:29+0000\n" "Last-Translator: mymage \n" "Language-Team: none\n" "Language: it\n" From c518aa6d4b3fc35382b256ae396d3f00ad70214f Mon Sep 17 00:00:00 2001 From: Anonymous Date: Wed, 25 Feb 2026 07:27:16 +0000 Subject: [PATCH 20/24] Translated using Weblate (Italian) Currently translated at 100.0% (14 of 14 strings) Translation: e-commerce-18.0/e-commerce-18.0-website_sale_cart_expire Translate-URL: https://translation.odoo-community.org/projects/e-commerce-18-0/e-commerce-18-0-website_sale_cart_expire/it/ --- website_sale_cart_expire/i18n/it.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website_sale_cart_expire/i18n/it.po b/website_sale_cart_expire/i18n/it.po index a005ad054a..be4f18a4d4 100644 --- a/website_sale_cart_expire/i18n/it.po +++ b/website_sale_cart_expire/i18n/it.po @@ -7,7 +7,7 @@ msgstr "" "Project-Id-Version: Odoo Server 16.0\n" "Report-Msgid-Bugs-To: \n" "PO-Revision-Date: 2026-02-25 07:29+0000\n" -"Last-Translator: mymage \n" +"Last-Translator: Anonymous \n" "Language-Team: none\n" "Language: it\n" "MIME-Version: 1.0\n" From 3ecb543f9abe728931eb933b2840ab7bfd470cf7 Mon Sep 17 00:00:00 2001 From: Anonymous Date: Wed, 25 Feb 2026 07:26:49 +0000 Subject: [PATCH 21/24] Translated using Weblate (Spanish) Currently translated at 78.5% (11 of 14 strings) Translation: e-commerce-18.0/e-commerce-18.0-website_sale_cart_expire Translate-URL: https://translation.odoo-community.org/projects/e-commerce-18-0/e-commerce-18-0-website_sale_cart_expire/es/ --- website_sale_cart_expire/i18n/es.po | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/website_sale_cart_expire/i18n/es.po b/website_sale_cart_expire/i18n/es.po index ead43b55a5..d776daf35c 100644 --- a/website_sale_cart_expire/i18n/es.po +++ b/website_sale_cart_expire/i18n/es.po @@ -6,15 +6,15 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 16.0\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2023-08-03 20:09+0000\n" -"Last-Translator: Ivorra78 \n" +"PO-Revision-Date: 2026-02-25 07:30+0000\n" +"Last-Translator: Anonymous \n" "Language-Team: none\n" "Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: \n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.17\n" +"X-Generator: Weblate 5.15.2\n" #. module: website_sale_cart_expire #: model_terms:ir.ui.view,arch_db:website_sale_cart_expire.res_config_settings_view_form From 9bcbb8c5c86a422afe84f716df66c7fc399c1265 Mon Sep 17 00:00:00 2001 From: Maksym Yankin Date: Thu, 12 Mar 2026 17:57:27 +0200 Subject: [PATCH 22/24] [MIG] website_sale_cart_expire: Migration to 19.0 --- website_sale_cart_expire/README.rst | 10 ++-- website_sale_cart_expire/__manifest__.py | 2 +- website_sale_cart_expire/models/website.py | 33 ++++++------ .../static/description/index.html | 6 +-- .../tests/test_website_sale_cart_expire.py | 51 +++++++++++++++---- .../views/res_config_settings.xml | 25 ++++----- 6 files changed, 77 insertions(+), 50 deletions(-) diff --git a/website_sale_cart_expire/README.rst b/website_sale_cart_expire/README.rst index 672d54ab6d..244fb2dd41 100644 --- a/website_sale_cart_expire/README.rst +++ b/website_sale_cart_expire/README.rst @@ -21,13 +21,13 @@ Website Sale Cart Expire :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fe--commerce-lightgray.png?logo=github - :target: https://github.com/OCA/e-commerce/tree/18.0/website_sale_cart_expire + :target: https://github.com/OCA/e-commerce/tree/19.0/website_sale_cart_expire :alt: OCA/e-commerce .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png - :target: https://translation.odoo-community.org/projects/e-commerce-18-0/e-commerce-18-0-website_sale_cart_expire + :target: https://translation.odoo-community.org/projects/e-commerce-19-0/e-commerce-19-0-website_sale_cart_expire :alt: Translate me on Weblate .. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png - :target: https://runboat.odoo-community.org/builds?repo=OCA/e-commerce&target_branch=18.0 + :target: https://runboat.odoo-community.org/builds?repo=OCA/e-commerce&target_branch=19.0 :alt: Try me on Runboat |badge1| |badge2| |badge3| |badge4| |badge5| @@ -51,7 +51,7 @@ Bug Tracker Bugs are tracked on `GitHub Issues `_. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed -`feedback `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -91,6 +91,6 @@ Current `maintainer `__: |maintainer-ivantodorovich| -This module is part of the `OCA/e-commerce `_ project on GitHub. +This module is part of the `OCA/e-commerce `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/website_sale_cart_expire/__manifest__.py b/website_sale_cart_expire/__manifest__.py index db5a57c86e..30caab2d0d 100644 --- a/website_sale_cart_expire/__manifest__.py +++ b/website_sale_cart_expire/__manifest__.py @@ -5,7 +5,7 @@ { "name": "Website Sale Cart Expire", "summary": "Cancel carts without activity after a configurable time", - "version": "18.0.1.0.1", + "version": "19.0.1.0.0", "author": "Camptocamp, Odoo Community Association (OCA)", "maintainers": ["ivantodorovich"], "website": "https://github.com/OCA/e-commerce", diff --git a/website_sale_cart_expire/models/website.py b/website_sale_cart_expire/models/website.py index 14e2fc1bf7..2c4a16c74b 100644 --- a/website_sale_cart_expire/models/website.py +++ b/website_sale_cart_expire/models/website.py @@ -5,8 +5,8 @@ import logging from datetime import timedelta -from odoo import _, api, fields, models -from odoo.osv import expression +from odoo import api, fields, models +from odoo.fields import Domain _logger = logging.getLogger(__name__) @@ -24,26 +24,27 @@ class Website(models.Model): def _get_cart_expire_delay_domain(self): self.ensure_one() expire_date = fields.Datetime.now() - timedelta(hours=self.cart_expire_delay) - return [ - ("website_id", "=", self.id), - ("state", "=", "draft"), - ("write_date", "<=", expire_date), + return ( + Domain("website_id", "=", self.id) + & Domain("state", "=", "draft") + & Domain("write_date", "<=", expire_date) # We don't want to cancel carts that are already in payment. - "|", - ("transaction_ids", "=", False), - "!", - ("transaction_ids.state", "in", ["pending", "authorized", "done"]), - ] + & ( + Domain( + "transaction_ids", + "not any", + Domain("state", "in", ["pending", "authorized", "done"]), + ) + ) + ) @api.model def _scheduler_website_expire_cart(self, autocommit=False): - websites = self.search([("cart_expire_delay", ">", 0)]) + websites = self.search(Domain("cart_expire_delay", ">", 0)) if not websites: return True carts = self.env["sale.order"].search( - expression.OR( - [website._get_cart_expire_delay_domain() for website in websites] - ) + Domain.OR([website._get_cart_expire_delay_domain() for website in websites]) ) now = fields.Datetime.now() for cart in carts: @@ -51,7 +52,7 @@ def _scheduler_website_expire_cart(self, autocommit=False): continue try: with self.env.cr.savepoint(): - cart.message_post(body=_("Cart expired")) + cart.message_post(body=self.env._("Cart expired")) cart.action_cancel() except Exception as e: _logger.exception("Unable to cancel expired cart %s: %s", cart, e) diff --git a/website_sale_cart_expire/static/description/index.html b/website_sale_cart_expire/static/description/index.html index 50f1590c5b..a5d9d72169 100644 --- a/website_sale_cart_expire/static/description/index.html +++ b/website_sale_cart_expire/static/description/index.html @@ -374,7 +374,7 @@

Website Sale Cart Expire

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! source digest: sha256:28205d71c6d2fdcccdd83f01fbda5702434747419aff45e4c62775e2f2114b06 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> -

Beta License: AGPL-3 OCA/e-commerce Translate me on Weblate Try me on Runboat

+

Beta License: AGPL-3 OCA/e-commerce Translate me on Weblate Try me on Runboat

Allows to automatically cancel carts without activity after a configurable time.

Table of contents

@@ -399,7 +399,7 @@

Bug Tracker

Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed -feedback.

+feedback.

Do not contact contributors directly about support or help with technical issues.

@@ -433,7 +433,7 @@

Maintainers

promote its widespread use.

Current maintainer:

ivantodorovich

-

This module is part of the OCA/e-commerce project on GitHub.

+

This module is part of the OCA/e-commerce project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

diff --git a/website_sale_cart_expire/tests/test_website_sale_cart_expire.py b/website_sale_cart_expire/tests/test_website_sale_cart_expire.py index b211ee8a92..b12b9e0134 100644 --- a/website_sale_cart_expire/tests/test_website_sale_cart_expire.py +++ b/website_sale_cart_expire/tests/test_website_sale_cart_expire.py @@ -6,7 +6,7 @@ from freezegun import freeze_time -from odoo import fields +from odoo import Command, fields from odoo.addons.base.tests.common import BaseCommon @@ -18,22 +18,51 @@ def setUpClass(cls): cls.tx_counter = 0 # Websites cls.website_1 = cls.env.ref("website.default_website") - cls.website_2 = cls.env.ref("website.website2") + cls.website_2 = cls.env["website"].create( + {"name": "My Website 2", "sequence": 20} + ) cls.website_1.cart_expire_delay = 0.00 # hours (= disabled) cls.website_2.cart_expire_delay = 2.00 # hours + cls.partner = cls.env["res.partner"].create({"name": "Test"}) + cls.product = cls.env["product.product"].create( + { + "name": "Desk Combination", + "type": "consu", + } + ) # Orders - cls.order_1 = cls.env.ref("website_sale.website_sale_order_1") - cls.order_2 = cls.env.ref("website_sale.website_sale_order_2") - cls.order_3 = cls.env.ref("website_sale.website_sale_order_3") - cls.order_4 = cls.env.ref("website_sale.website_sale_order_4") - cls.orders = cls.order_1 + cls.order_2 + cls.order_3 + cls.order_4 - # Set to draft and assign all to website_2 - # (this also updates write_date to now()) - cls.orders.write({"state": "draft", "website_id": cls.website_2.id}) + cls.order_1 = cls._create_cart_order() + cls.order_2 = cls._create_cart_order() + cls.order_3 = cls._create_cart_order() + cls.order_4 = cls._create_cart_order() + cls.orders = cls.order_1 | cls.order_2 | cls.order_3 | cls.order_4 cls.payment_method = cls.env["payment.method"].create( {"name": "Test_method", "code": "123"} ) + @classmethod + def _create_cart_order(cls): + return cls.env["sale.order"].create( + { + "partner_id": cls.partner.id, + "partner_invoice_id": cls.partner.id, + "partner_shipping_id": cls.partner.id, + # Set to draft and assign all to website_2 + # (this also updates write_date to now()) + "website_id": cls.website_2.id, + "state": "draft", + "order_line": [ + Command.create( + { + "product_id": cls.product.id, + "product_uom_qty": 1.0, + "price_unit": 100.0, + }, + ) + ], + } + ) + def _create_payment_transaction(self, order): self.tx_counter += 1 provider = self.env.ref("payment.payment_provider_transfer") @@ -77,7 +106,7 @@ def test_expire_scheduler(self): def test_expire_scheduler_multi_website(self): # For this test, we split the orders among the 2 websites - (self.order_1 + self.order_2).write({"website_id": self.website_1.id}) + (self.order_1 | self.order_2).write({"website_id": self.website_1.id}) with freeze_time(datetime.now() + timedelta(hours=3)): self.env["website"]._scheduler_website_expire_cart() self.assertEqual(self.order_1.state, "draft", "No expire delay on website 1") diff --git a/website_sale_cart_expire/views/res_config_settings.xml b/website_sale_cart_expire/views/res_config_settings.xml index 8a7d04e257..b08ce55c5a 100644 --- a/website_sale_cart_expire/views/res_config_settings.xml +++ b/website_sale_cart_expire/views/res_config_settings.xml @@ -10,29 +10,26 @@ - -