From a1b5d622f5383419d86ada0c6b8bb0c5d0354c15 Mon Sep 17 00:00:00 2001 From: JasminSForgeFlow Date: Tue, 19 May 2026 05:17:05 +0000 Subject: [PATCH] [ADD] website_sale_checkout_skip_payment_quotation --- .../README.rst | 121 +++++ .../__init__.py | 2 + .../__manifest__.py | 20 + .../controllers/__init__.py | 1 + .../controllers/main.py | 55 ++ .../data/mail_template_data.xml | 65 +++ .../models/__init__.py | 2 + .../models/sale_order.py | 19 + .../models/website.py | 18 + .../pyproject.toml | 3 + .../readme/CONTRIBUTORS.md | 2 + .../readme/DESCRIPTION.md | 16 + .../readme/USAGE.md | 19 + .../static/description/index.html | 472 ++++++++++++++++++ .../views/website_sale_template.xml | 17 + 15 files changed, 832 insertions(+) create mode 100644 website_sale_checkout_skip_payment_quotation/README.rst create mode 100644 website_sale_checkout_skip_payment_quotation/__init__.py create mode 100644 website_sale_checkout_skip_payment_quotation/__manifest__.py create mode 100644 website_sale_checkout_skip_payment_quotation/controllers/__init__.py create mode 100644 website_sale_checkout_skip_payment_quotation/controllers/main.py create mode 100644 website_sale_checkout_skip_payment_quotation/data/mail_template_data.xml create mode 100644 website_sale_checkout_skip_payment_quotation/models/__init__.py create mode 100644 website_sale_checkout_skip_payment_quotation/models/sale_order.py create mode 100644 website_sale_checkout_skip_payment_quotation/models/website.py create mode 100644 website_sale_checkout_skip_payment_quotation/pyproject.toml create mode 100644 website_sale_checkout_skip_payment_quotation/readme/CONTRIBUTORS.md create mode 100644 website_sale_checkout_skip_payment_quotation/readme/DESCRIPTION.md create mode 100644 website_sale_checkout_skip_payment_quotation/readme/USAGE.md create mode 100644 website_sale_checkout_skip_payment_quotation/static/description/index.html create mode 100644 website_sale_checkout_skip_payment_quotation/views/website_sale_template.xml diff --git a/website_sale_checkout_skip_payment_quotation/README.rst b/website_sale_checkout_skip_payment_quotation/README.rst new file mode 100644 index 0000000000..8ca608eff9 --- /dev/null +++ b/website_sale_checkout_skip_payment_quotation/README.rst @@ -0,0 +1,121 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + +====================================================== +Website Sale Checkout Skip Payment - Keep as Quotation +====================================================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:54e6991977b71c755358a192904f67116f3052f0b94266f10ef2a6ef4ce86503 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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/license-LGPL--3-blue.png + :target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html + :alt: License: LGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fe--commerce-lightgray.png?logo=github + :target: https://github.com/OCA/e-commerce/tree/19.0/website_sale_checkout_skip_payment_quotation + :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-19-0/e-commerce-19-0-website_sale_checkout_skip_payment_quotation + :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=19.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module extends *Website Sale Checkout Skip Payment* so that, when a +logged-in customer with the *Skip Website Checkout Payment* flag +completes the website checkout: + +- the order is **not** automatically confirmed and stays in *Quotation* + (draft) state, waiting for a salesperson to review it; +- a dedicated email template (*Sales: Quotation Sent (Skip Payment)*) is + sent to the customer to acknowledge the request, instead of the + standard sale order confirmation email; +- the order is flagged so the website cart resolver will **not** + resurrect it as the customer's active cart on subsequent visits. The + customer starts from an empty cart on their next visit. + +This is useful for B2B scenarios where every order has to be reviewed by +a salesperson before it is confirmed, while still letting the customer +finalise the checkout flow without going through a payment step. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +To use this module, you need to: + +1. Configure *Website Sale Checkout Skip Payment* as documented in that + module (enable *Checkout Skip Payment* on the website and tick *Skip + Website Checkout Payment* on the customer). +2. Optionally adjust the email content in *Settings > Technical > Email + Templates > Sales: Quotation Sent (Skip Payment)*. +3. Perform a checkout from the website with that customer. + +Expected outcome: + +- The order is created in *Sales > Quotations* in **Quotation** (draft) + state. No sales order is confirmed and no stock is reserved. +- The customer receives the *Sales: Quotation Sent (Skip Payment)* + email. +- The customer's cart is emptied; visiting the shop again starts a new + cart instead of reopening the just-submitted quotation. +- The quotation is flagged with *Skip-Payment Quotation* so a + salesperson can identify orders that originated from this flow before + confirming them manually. + +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 `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* ForgeFlow + +Contributors +------------ + +- `ForgeFlow `__: + + - Jasmin Solanki + +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. + +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_checkout_skip_payment_quotation/__init__.py b/website_sale_checkout_skip_payment_quotation/__init__.py new file mode 100644 index 0000000000..91c5580fed --- /dev/null +++ b/website_sale_checkout_skip_payment_quotation/__init__.py @@ -0,0 +1,2 @@ +from . import controllers +from . import models diff --git a/website_sale_checkout_skip_payment_quotation/__manifest__.py b/website_sale_checkout_skip_payment_quotation/__manifest__.py new file mode 100644 index 0000000000..2bd573fa16 --- /dev/null +++ b/website_sale_checkout_skip_payment_quotation/__manifest__.py @@ -0,0 +1,20 @@ +# Copyright 2026 ForgeFlow S.L. +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +{ + "name": "Website Sale Checkout Skip Payment - Keep as Quotation", + "summary": "Skip payment in checkout and keep the order as a quotation, " + "notifying the customer with a dedicated email template.", + "version": "19.0.1.0.0", + "category": "Website", + "website": "https://github.com/OCA/e-commerce", + "author": "ForgeFlow, Odoo Community Association (OCA)", + "license": "LGPL-3", + "application": False, + "installable": True, + "depends": ["website_sale_checkout_skip_payment"], + "data": [ + "data/mail_template_data.xml", + "views/website_sale_template.xml", + ], +} diff --git a/website_sale_checkout_skip_payment_quotation/controllers/__init__.py b/website_sale_checkout_skip_payment_quotation/controllers/__init__.py new file mode 100644 index 0000000000..12a7e529b6 --- /dev/null +++ b/website_sale_checkout_skip_payment_quotation/controllers/__init__.py @@ -0,0 +1 @@ +from . import main diff --git a/website_sale_checkout_skip_payment_quotation/controllers/main.py b/website_sale_checkout_skip_payment_quotation/controllers/main.py new file mode 100644 index 0000000000..2888e3af2a --- /dev/null +++ b/website_sale_checkout_skip_payment_quotation/controllers/main.py @@ -0,0 +1,55 @@ +# Copyright 2026 ForgeFlow S.L. +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +import logging + +from odoo import http +from odoo.http import request + +from odoo.addons.website_sale_checkout_skip_payment.controllers.main import ( + CheckoutSkipPaymentWebsite, +) + +_logger = logging.getLogger(__name__) + + +class CheckoutSkipPaymentQuotation(CheckoutSkipPaymentWebsite): + @http.route() + def shop_payment_confirmation(self, **post): + """When skipping payment, keep the order as a quotation (do not confirm) + and notify the customer with the dedicated quotation email template. + """ + order_id = request.session.get("sale_last_order_id") + if not request.website.checkout_skip_payment or not order_id: + return super().shop_payment_confirmation(**post) + order = request.env["sale.order"].sudo().browse(order_id) + template = request.env.ref( + "website_sale_checkout_skip_payment_quotation." + "mail_template_sale_quotation_skip_payment", + raise_if_not_found=False, + ) + if not template: + _logger.warning( + "Quotation skip-payment mail template not found; " + "falling back to parent behaviour." + ) + return super().shop_payment_confirmation(**post) + try: + # Note: we deliberately do NOT pass ``mark_so_as_sent=True`` here so the + # order stays in ``draft`` (Quotation) state. The parent module passes + # that context flag, which would move the state to ``sent``. + order._send_order_notification_mail(template) + # Flag the order so the website cart resolver does not resurrect it + # as an abandoned cart on the customer's next visit. See + # ``website._get_and_cache_current_cart`` override in this module. + order.is_skip_payment_quotation = True + except Exception: + _logger.exception( + "Failed to send quotation confirmation email for order %s", order.name + ) + return request.render( + "website_sale_checkout_skip_payment.confirmation_order_error" + ) + request.website.sale_reset() + values = self._prepare_shop_payment_confirmation_values(order) + return request.render("website_sale.confirmation", values) diff --git a/website_sale_checkout_skip_payment_quotation/data/mail_template_data.xml b/website_sale_checkout_skip_payment_quotation/data/mail_template_data.xml new file mode 100644 index 0000000000..884302698f --- /dev/null +++ b/website_sale_checkout_skip_payment_quotation/data/mail_template_data.xml @@ -0,0 +1,65 @@ + + + + + Sales: Quotation Sent (Skip Payment) + + {{ object.company_id.name }} Quotation (Ref {{ object.name or 'n/a' }}) + {{ (object.user_id.email_formatted or object.company_id.email_formatted or user.email_formatted) }} + + + Sent to website customers after a skip-payment checkout. The order remains a quotation. + +
+

+ Hello + Customer, +
+
+ Thank you for your interest. We have received your request + S00049 + for a total of + $ 10.00. +
+
+ Your quotation is being reviewed by our team and you will receive + a confirmation as soon as it is processed. +
+
+ You can review the details of your quotation at any time using the link below: +
+
+ View your quotation +
+
+ If you have any question, simply reply to this email. +
+
+ Best regards, +
+ Sales Team +

+
+
+ {{ object.partner_id.lang }} + +
+
diff --git a/website_sale_checkout_skip_payment_quotation/models/__init__.py b/website_sale_checkout_skip_payment_quotation/models/__init__.py new file mode 100644 index 0000000000..71db68c22d --- /dev/null +++ b/website_sale_checkout_skip_payment_quotation/models/__init__.py @@ -0,0 +1,2 @@ +from . import sale_order +from . import website diff --git a/website_sale_checkout_skip_payment_quotation/models/sale_order.py b/website_sale_checkout_skip_payment_quotation/models/sale_order.py new file mode 100644 index 0000000000..46abaf2a8f --- /dev/null +++ b/website_sale_checkout_skip_payment_quotation/models/sale_order.py @@ -0,0 +1,19 @@ +# Copyright 2026 ForgeFlow S.L. +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +from odoo import fields, models + + +class SaleOrder(models.Model): + _inherit = "sale.order" + + is_skip_payment_quotation = fields.Boolean( + # Set on orders that completed the website checkout via the + # skip-payment flow. These quotations must not be resurrected as the + # customer's cart on subsequent visits, otherwise the website would + # keep showing the items the customer already "ordered". + string="Skip-Payment Quotation", + copy=False, + readonly=True, + index=True, + ) diff --git a/website_sale_checkout_skip_payment_quotation/models/website.py b/website_sale_checkout_skip_payment_quotation/models/website.py new file mode 100644 index 0000000000..03670de414 --- /dev/null +++ b/website_sale_checkout_skip_payment_quotation/models/website.py @@ -0,0 +1,18 @@ +# Copyright 2026 ForgeFlow S.L. +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +from odoo import models + + +class Website(models.Model): + _inherit = "website" + + def _get_and_cache_current_cart(self): + sale_order_sudo = super()._get_and_cache_current_cart() + # Skip-payment quotations have been "handed off" to the salesperson; + # they must not be resurrected as the active cart, even though they + # remain in draft state. + if sale_order_sudo and sale_order_sudo.is_skip_payment_quotation: + self.sale_reset() + return self.env["sale.order"].sudo() + return sale_order_sudo diff --git a/website_sale_checkout_skip_payment_quotation/pyproject.toml b/website_sale_checkout_skip_payment_quotation/pyproject.toml new file mode 100644 index 0000000000..4231d0cccb --- /dev/null +++ b/website_sale_checkout_skip_payment_quotation/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/website_sale_checkout_skip_payment_quotation/readme/CONTRIBUTORS.md b/website_sale_checkout_skip_payment_quotation/readme/CONTRIBUTORS.md new file mode 100644 index 0000000000..6fa71c05bf --- /dev/null +++ b/website_sale_checkout_skip_payment_quotation/readme/CONTRIBUTORS.md @@ -0,0 +1,2 @@ +- [ForgeFlow](https://www.forgeflow.com): + - Jasmin Solanki \<\> diff --git a/website_sale_checkout_skip_payment_quotation/readme/DESCRIPTION.md b/website_sale_checkout_skip_payment_quotation/readme/DESCRIPTION.md new file mode 100644 index 0000000000..1eb6c32d1b --- /dev/null +++ b/website_sale_checkout_skip_payment_quotation/readme/DESCRIPTION.md @@ -0,0 +1,16 @@ +This module extends *Website Sale Checkout Skip Payment* so that, when a +logged-in customer with the *Skip Website Checkout Payment* flag completes +the website checkout: + +- the order is **not** automatically confirmed and stays in *Quotation* + (draft) state, waiting for a salesperson to review it; +- a dedicated email template (*Sales: Quotation Sent (Skip Payment)*) is + sent to the customer to acknowledge the request, instead of the standard + sale order confirmation email; +- the order is flagged so the website cart resolver will **not** resurrect + it as the customer's active cart on subsequent visits. The customer + starts from an empty cart on their next visit. + +This is useful for B2B scenarios where every order has to be reviewed by +a salesperson before it is confirmed, while still letting the customer +finalise the checkout flow without going through a payment step. diff --git a/website_sale_checkout_skip_payment_quotation/readme/USAGE.md b/website_sale_checkout_skip_payment_quotation/readme/USAGE.md new file mode 100644 index 0000000000..dc650e7a13 --- /dev/null +++ b/website_sale_checkout_skip_payment_quotation/readme/USAGE.md @@ -0,0 +1,19 @@ +To use this module, you need to: + +1. Configure *Website Sale Checkout Skip Payment* as documented in that + module (enable *Checkout Skip Payment* on the website and tick + *Skip Website Checkout Payment* on the customer). +2. Optionally adjust the email content in *Settings \> Technical \> + Email Templates \> Sales: Quotation Sent (Skip Payment)*. +3. Perform a checkout from the website with that customer. + +Expected outcome: + +- The order is created in *Sales \> Quotations* in **Quotation** (draft) + state. No sales order is confirmed and no stock is reserved. +- The customer receives the *Sales: Quotation Sent (Skip Payment)* email. +- The customer's cart is emptied; visiting the shop again starts a new + cart instead of reopening the just-submitted quotation. +- The quotation is flagged with *Skip-Payment Quotation* so a salesperson + can identify orders that originated from this flow before confirming + them manually. diff --git a/website_sale_checkout_skip_payment_quotation/static/description/index.html b/website_sale_checkout_skip_payment_quotation/static/description/index.html new file mode 100644 index 0000000000..3a266f54e4 --- /dev/null +++ b/website_sale_checkout_skip_payment_quotation/static/description/index.html @@ -0,0 +1,472 @@ + + + + + +README.rst + + + +
+ + + +Odoo Community Association + +
+

Website Sale Checkout Skip Payment - Keep as Quotation

+ +

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

+

This module extends Website Sale Checkout Skip Payment so that, when a +logged-in customer with the Skip Website Checkout Payment flag +completes the website checkout:

+
    +
  • the order is not automatically confirmed and stays in Quotation +(draft) state, waiting for a salesperson to review it;
  • +
  • a dedicated email template (Sales: Quotation Sent (Skip Payment)) is +sent to the customer to acknowledge the request, instead of the +standard sale order confirmation email;
  • +
  • the order is flagged so the website cart resolver will not +resurrect it as the customer’s active cart on subsequent visits. The +customer starts from an empty cart on their next visit.
  • +
+

This is useful for B2B scenarios where every order has to be reviewed by +a salesperson before it is confirmed, while still letting the customer +finalise the checkout flow without going through a payment step.

+

Table of contents

+ +
+

Usage

+

To use this module, you need to:

+
    +
  1. Configure Website Sale Checkout Skip Payment as documented in that +module (enable Checkout Skip Payment on the website and tick Skip +Website Checkout Payment on the customer).
  2. +
  3. Optionally adjust the email content in Settings > Technical > Email +Templates > Sales: Quotation Sent (Skip Payment).
  4. +
  5. Perform a checkout from the website with that customer.
  6. +
+

Expected outcome:

+
    +
  • The order is created in Sales > Quotations in Quotation (draft) +state. No sales order is confirmed and no stock is reserved.
  • +
  • The customer receives the Sales: Quotation Sent (Skip Payment) +email.
  • +
  • The customer’s cart is emptied; visiting the shop again starts a new +cart instead of reopening the just-submitted quotation.
  • +
  • The quotation is flagged with Skip-Payment Quotation so a +salesperson can identify orders that originated from this flow before +confirming them manually.
  • +
+
+
+

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.

+

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

+
+
+

Credits

+
+

Authors

+
    +
  • ForgeFlow
  • +
+
+
+

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.

+

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_checkout_skip_payment_quotation/views/website_sale_template.xml b/website_sale_checkout_skip_payment_quotation/views/website_sale_template.xml new file mode 100644 index 0000000000..9ae3dff7e8 --- /dev/null +++ b/website_sale_checkout_skip_payment_quotation/views/website_sale_template.xml @@ -0,0 +1,17 @@ + + + + +