Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions website_sale_product_inquiry/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
.. image:: https://odoo-community.org/readme-banner-image
:target: https://odoo-community.org/get-involved?utm_source=readme
:alt: Odoo Community Association

============================
Website Sale Product Inquiry
============================

..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:67a6973b26a2aa8a8020bba567ab27e04f818376baa9c0254cd48825b00fbcc9
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |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-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/19.0/website_sale_product_inquiry
: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_product_inquiry
: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|

Adds a **Request Information** button to each product page in the
eCommerce shop. Clicking the button opens a modal form where the visitor
selects a request type (*More Information* or *Quote*), fills in their
contact details, and submits.

A CRM lead is created automatically from the submission, pre-linked to
the enquired product. Downstream glue modules can override
``ProductInquiryController._get_product_salesperson`` to assign a
specific salesperson based on product-level ownership data.

**Table of contents**

.. contents::
:local:

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/OCA/e-commerce/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 <https://github.com/OCA/e-commerce/issues/new?body=module:%20website_sale_product_inquiry%0Aversion:%2019.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

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

Credits
=======

Authors
-------

* ForgeFlow

Contributors
------------

- `ForgeFlow <https://www.forgeflow.com>`__:

- 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 <https://github.com/OCA/e-commerce/tree/19.0/website_sale_product_inquiry>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
2 changes: 2 additions & 0 deletions website_sale_product_inquiry/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import controllers
from . import models
26 changes: 26 additions & 0 deletions website_sale_product_inquiry/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Copyright 2026 ForgeFlow S.L.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
{
"name": "Website Sale Product Inquiry",
"summary": "Add a product inquiry button and popup form on eCommerce product pages",
"version": "19.0.1.0.0",
"category": "Website",
"website": "https://github.com/OCA/e-commerce",
"author": "ForgeFlow, Odoo Community Association (OCA)",
"license": "AGPL-3",
"application": False,
"installable": True,
"depends": [
"website_sale",
"crm",
],
"data": [
"views/crm_lead_views.xml",
"views/templates.xml",
],
"assets": {
"web.assets_frontend": [
"website_sale_product_inquiry/static/src/js/product_inquiry.esm.js",
],
},
}
4 changes: 4 additions & 0 deletions website_sale_product_inquiry/controllers/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright 2026 ForgeFlow S.L.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

Comment on lines +1 to +3

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Copyright 2026 ForgeFlow S.L.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

nitpicking: not needed in init.py files

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated, Thanks

from . import main
81 changes: 81 additions & 0 deletions website_sale_product_inquiry/controllers/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Copyright 2026 ForgeFlow S.L.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

import base64

from odoo import http
from odoo.http import request


class ProductInquiryController(http.Controller):
@http.route(
"/shop/product/inquiry",
type="http",
auth="public",
methods=["POST"],
website=True,
csrf=False,
)
def product_inquiry(self, **kwargs):
product_id = kwargs.get("product_id", "").strip()
contact_name = kwargs.get("contact_name", "").strip()
email = kwargs.get("email", "").strip()
phone = kwargs.get("phone", "").strip()
company_name = kwargs.get("company_name", "").strip()
inquiry_type = kwargs.get("inquiry_type", "more_info")
question = kwargs.get("question", "").strip()

if not product_id or not contact_name or not email or not question:
return request.make_json_response(
{"success": False, "error": "Required fields are missing."},
status=400,
)
try:
product_id = int(product_id)
except (ValueError, TypeError):
return request.make_json_response(
{"success": False, "error": "Invalid product."}, status=400
)
variant = request.env["product.product"].sudo().browse(product_id)
if not variant.exists():
return request.make_json_response(
{"success": False, "error": "Product not found."}, status=404
)
description = f"<p>{question}</p>"
lead_vals = {
"name": f"Product inquiry: {variant.product_tmpl_id.name}",
"contact_name": contact_name,
"email_from": email,
"phone": phone or False,
"partner_name": company_name or False,
"inquired_product_id": variant.id,
"inquiry_type": inquiry_type,
"description": description,
"type": "lead",
"company_id": request.website.company_id.id,
}
salesperson_id = self._get_product_salesperson(variant) # pylint: disable=assignment-from-none
if salesperson_id is not None:
lead_vals["user_id"] = salesperson_id or False
lead = request.env["crm.lead"].sudo().create(lead_vals)
attachment_file = kwargs.get("attachment")
if attachment_file and hasattr(attachment_file, "read"):
data = attachment_file.read()
if data:
request.env["ir.attachment"].sudo().create(
{
"name": attachment_file.filename,
"datas": base64.b64encode(data),
"res_model": "crm.lead",
"res_id": lead.id,
}
)
return request.make_json_response({"success": True})

def _get_product_salesperson(self, variant):
"""Return salesperson assignment for the lead.
- Return a user ID to assign that user.
- Return False to explicitly leave user_id blank.
- Return None (default) to let the model default apply.
"""
return None
4 changes: 4 additions & 0 deletions website_sale_product_inquiry/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright 2026 ForgeFlow S.L.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from . import crm_lead
20 changes: 20 additions & 0 deletions website_sale_product_inquiry/models/crm_lead.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Copyright 2026 ForgeFlow S.L.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from odoo import fields, models


class CrmLead(models.Model):
_inherit = "crm.lead"

inquired_product_id = fields.Many2one(
"product.product",
string="Product",
ondelete="set null",
)
inquiry_type = fields.Selection(
[
("more_info", "More Information"),
("quote", "Quote"),
],
)
3 changes: 3 additions & 0 deletions website_sale_product_inquiry/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[build-system]
requires = ["whool"]
build-backend = "whool.buildapi"
2 changes: 2 additions & 0 deletions website_sale_product_inquiry/readme/CONTRIBUTORS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- [ForgeFlow](https://www.forgeflow.com):
- Jasmin Solanki
8 changes: 8 additions & 0 deletions website_sale_product_inquiry/readme/DESCRIPTION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Adds a **Request Information** button to each product page in the eCommerce shop.
Clicking the button opens a modal form where the visitor selects a request type
(*More Information* or *Quote*), fills in their contact details, and submits.

A CRM lead is created automatically from the submission, pre-linked to the
enquired product. Downstream glue modules can override
`ProductInquiryController._get_product_salesperson` to assign a specific
salesperson based on product-level ownership data.
Loading
Loading