Skip to content

Commit e62d7de

Browse files
JasminSForgeFlowDavidJForgeFlow
authored andcommitted
[ADD] website_sale_product_inquiry
1 parent 25bf7fa commit e62d7de

14 files changed

Lines changed: 1047 additions & 0 deletions

File tree

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
.. image:: https://odoo-community.org/readme-banner-image
2+
:target: https://odoo-community.org/get-involved?utm_source=readme
3+
:alt: Odoo Community Association
4+
5+
============================
6+
Website Sale Product Inquiry
7+
============================
8+
9+
..
10+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
11+
!! This file is generated by oca-gen-addon-readme !!
12+
!! changes will be overwritten. !!
13+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
14+
!! source digest: sha256:67a6973b26a2aa8a8020bba567ab27e04f818376baa9c0254cd48825b00fbcc9
15+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
16+
17+
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
18+
:target: https://odoo-community.org/page/development-status
19+
:alt: Beta
20+
.. |badge2| image:: https://img.shields.io/badge/license-AGPL--3-blue.png
21+
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
22+
:alt: License: AGPL-3
23+
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fe--commerce-lightgray.png?logo=github
24+
:target: https://github.com/OCA/e-commerce/tree/19.0/website_sale_product_inquiry
25+
:alt: OCA/e-commerce
26+
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
27+
:target: https://translation.odoo-community.org/projects/e-commerce-19-0/e-commerce-19-0-website_sale_product_inquiry
28+
:alt: Translate me on Weblate
29+
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
30+
:target: https://runboat.odoo-community.org/builds?repo=OCA/e-commerce&target_branch=19.0
31+
:alt: Try me on Runboat
32+
33+
|badge1| |badge2| |badge3| |badge4| |badge5|
34+
35+
Adds a **Request Information** button to each product page in the
36+
eCommerce shop. Clicking the button opens a modal form where the visitor
37+
selects a request type (*More Information* or *Quote*), fills in their
38+
contact details, and submits.
39+
40+
A CRM lead is created automatically from the submission, pre-linked to
41+
the enquired product. Downstream glue modules can override
42+
``ProductInquiryController._get_product_salesperson`` to assign a
43+
specific salesperson based on product-level ownership data.
44+
45+
**Table of contents**
46+
47+
.. contents::
48+
:local:
49+
50+
Bug Tracker
51+
===========
52+
53+
Bugs are tracked on `GitHub Issues <https://github.com/OCA/e-commerce/issues>`_.
54+
In case of trouble, please check there if your issue has already been reported.
55+
If you spotted it first, help us to smash it by providing a detailed and welcomed
56+
`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**>`_.
57+
58+
Do not contact contributors directly about support or help with technical issues.
59+
60+
Credits
61+
=======
62+
63+
Authors
64+
-------
65+
66+
* ForgeFlow
67+
68+
Contributors
69+
------------
70+
71+
- `ForgeFlow <https://www.forgeflow.com>`__:
72+
73+
- Jasmin Solanki
74+
75+
Maintainers
76+
-----------
77+
78+
This module is maintained by the OCA.
79+
80+
.. image:: https://odoo-community.org/logo.png
81+
:alt: Odoo Community Association
82+
:target: https://odoo-community.org
83+
84+
OCA, or the Odoo Community Association, is a nonprofit organization whose
85+
mission is to support the collaborative development of Odoo features and
86+
promote its widespread use.
87+
88+
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.
89+
90+
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Copyright 2026 ForgeFlow S.L.
2+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
3+
4+
from . import controllers
5+
from . import models
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Copyright 2026 ForgeFlow S.L.
2+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
3+
{
4+
"name": "Website Sale Product Inquiry",
5+
"summary": "Add a product inquiry button and popup form on eCommerce product pages",
6+
"version": "19.0.1.0.0",
7+
"category": "Website",
8+
"website": "https://github.com/OCA/e-commerce",
9+
"author": "ForgeFlow, Odoo Community Association (OCA)",
10+
"license": "AGPL-3",
11+
"application": False,
12+
"installable": True,
13+
"depends": [
14+
"website_sale",
15+
"crm",
16+
],
17+
"data": [
18+
"views/crm_lead_views.xml",
19+
"views/templates.xml",
20+
],
21+
"assets": {
22+
"web.assets_frontend": [
23+
"website_sale_product_inquiry/static/src/js/product_inquiry.esm.js",
24+
],
25+
},
26+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Copyright 2026 ForgeFlow S.L.
2+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
3+
4+
from . import main
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# Copyright 2026 ForgeFlow S.L.
2+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
3+
4+
import base64
5+
6+
from odoo import http
7+
from odoo.http import request
8+
9+
10+
class ProductInquiryController(http.Controller):
11+
@http.route(
12+
"/shop/product/inquiry",
13+
type="http",
14+
auth="public",
15+
methods=["POST"],
16+
website=True,
17+
csrf=False,
18+
)
19+
def product_inquiry(self, **kwargs):
20+
product_id = kwargs.get("product_id", "").strip()
21+
contact_name = kwargs.get("contact_name", "").strip()
22+
email = kwargs.get("email", "").strip()
23+
phone = kwargs.get("phone", "").strip()
24+
company_name = kwargs.get("company_name", "").strip()
25+
inquiry_type = kwargs.get("inquiry_type", "more_info")
26+
question = kwargs.get("question", "").strip()
27+
28+
if not product_id or not contact_name or not email or not question:
29+
return request.make_json_response(
30+
{"success": False, "error": "Required fields are missing."},
31+
status=400,
32+
)
33+
try:
34+
product_id = int(product_id)
35+
except (ValueError, TypeError):
36+
return request.make_json_response(
37+
{"success": False, "error": "Invalid product."}, status=400
38+
)
39+
variant = request.env["product.product"].sudo().browse(product_id)
40+
if not variant.exists():
41+
return request.make_json_response(
42+
{"success": False, "error": "Product not found."}, status=404
43+
)
44+
description = f"<p>{question}</p>"
45+
lead_vals = {
46+
"name": f"Product inquiry: {variant.product_tmpl_id.name}",
47+
"contact_name": contact_name,
48+
"email_from": email,
49+
"phone": phone or False,
50+
"partner_name": company_name or False,
51+
"product_id": variant.id,
52+
"inquiry_type": inquiry_type,
53+
"description": description,
54+
"type": "lead",
55+
"company_id": request.website.company_id.id,
56+
}
57+
salesperson_id = self._get_product_salesperson(variant) # pylint: disable=assignment-from-none
58+
if salesperson_id is not None:
59+
lead_vals["user_id"] = salesperson_id or False
60+
lead = request.env["crm.lead"].sudo().create(lead_vals)
61+
attachment_file = kwargs.get("attachment")
62+
if attachment_file and hasattr(attachment_file, "read"):
63+
data = attachment_file.read()
64+
if data:
65+
request.env["ir.attachment"].sudo().create(
66+
{
67+
"name": attachment_file.filename,
68+
"datas": base64.b64encode(data),
69+
"res_model": "crm.lead",
70+
"res_id": lead.id,
71+
}
72+
)
73+
return request.make_json_response({"success": True})
74+
75+
def _get_product_salesperson(self, variant):
76+
"""Return salesperson assignment for the lead.
77+
- Return a user ID to assign that user.
78+
- Return False to explicitly leave user_id blank.
79+
- Return None (default) to let the model default apply.
80+
"""
81+
return None
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Copyright 2026 ForgeFlow S.L.
2+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
3+
4+
from . import crm_lead
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Copyright 2026 ForgeFlow S.L.
2+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
3+
4+
from odoo import fields, models
5+
6+
7+
class CrmLead(models.Model):
8+
_inherit = "crm.lead"
9+
10+
product_id = fields.Many2one(
11+
"product.product",
12+
string="Product",
13+
ondelete="set null",
14+
)
15+
inquiry_type = fields.Selection(
16+
[
17+
("more_info", "More Information"),
18+
("quote", "Quote"),
19+
],
20+
)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[build-system]
2+
requires = ["whool"]
3+
build-backend = "whool.buildapi"
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
- [ForgeFlow](https://www.forgeflow.com):
2+
- Jasmin Solanki
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Adds a **Request Information** button to each product page in the eCommerce shop.
2+
Clicking the button opens a modal form where the visitor selects a request type
3+
(*More Information* or *Quote*), fills in their contact details, and submits.
4+
5+
A CRM lead is created automatically from the submission, pre-linked to the
6+
enquired product. Downstream glue modules can override
7+
`ProductInquiryController._get_product_salesperson` to assign a specific
8+
salesperson based on product-level ownership data.

0 commit comments

Comments
 (0)