generic contact form

This commit is contained in:
Tobias Brunner 2025-02-27 15:44:55 +01:00
parent eece05af74
commit 2cbcc4ba98
No known key found for this signature in database
9 changed files with 280 additions and 48 deletions

View file

@ -0,0 +1,39 @@
# Generated by Django 5.1.5 on 2025-02-27 14:33
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("services", "0007_service_is_coming_soon"),
]
operations = [
migrations.AlterField(
model_name="lead",
name="company",
field=models.CharField(blank=True, max_length=200, null=True),
),
migrations.AlterField(
model_name="lead",
name="message",
field=models.TextField(blank=True, max_length=1000, null=True),
),
migrations.AlterField(
model_name="lead",
name="phone",
field=models.CharField(blank=True, max_length=50, null=True),
),
migrations.AlterField(
model_name="lead",
name="service",
field=models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to="services.service",
),
),
]

View file

@ -276,18 +276,22 @@ class ExternalLink(models.Model):
class Lead(models.Model):
service = models.ForeignKey(Service, on_delete=models.CASCADE)
name = models.CharField(max_length=200)
email = models.EmailField()
company = models.CharField(max_length=200, null=True, blank=True)
phone = models.CharField(max_length=50, null=True, blank=True)
message = models.TextField(blank=True, null=True, max_length=1000)
odoo_lead_id = models.IntegerField(null=True, blank=True)
service = models.ForeignKey(
Service, on_delete=models.SET_NULL, null=True, blank=True
)
offering = models.ForeignKey(
ServiceOffering, on_delete=models.SET_NULL, null=True, blank=True
)
plan = models.ForeignKey(Plan, on_delete=models.SET_NULL, null=True, blank=True)
name = models.CharField(max_length=200)
company = models.CharField(max_length=200)
email = models.EmailField()
phone = models.CharField(max_length=50)
message = models.TextField(blank=True, max_length=1000)
created_at = models.DateTimeField(auto_now_add=True)
odoo_lead_id = models.IntegerField(null=True, blank=True)
def __str__(self):
return f"{self.name} - {self.company} ({self.service})"

View file

@ -56,36 +56,48 @@ class OdooAPI:
def create_lead(self, lead, source="form"):
"""Create a lead in Odoo"""
try:
logger.info(
f"Attempting to create lead for {lead.name} from {lead.company}"
)
# Get provider name from offering if it exists
provider_name = ""
if hasattr(lead, "offering") and lead.offering:
provider_name = lead.offering.cloud_provider.name
logger.info(f"Attempting to create lead for {lead.name}")
# Prepare service description
service_details = []
if lead.service:
if hasattr(lead, "service") and lead.service:
service_details.append(f"Service: {lead.service.name}")
if provider_name:
service_details.append(f"Provider: {provider_name}")
if lead.plan:
service_details.append(f"Plan: {lead.plan.name}")
# Get provider name from offering if it exists
if (
hasattr(lead, "offering")
and lead.offering
and hasattr(lead.offering, "cloud_provider")
):
provider_name = lead.offering.cloud_provider.name
service_details.append(f"Provider: {provider_name}")
if hasattr(lead, "plan") and lead.plan:
service_details.append(f"Plan: {lead.plan.name}")
if source == "form":
service_details.append(f"Source: Servala Website")
elif source == "osbapi":
service_details.append(f"Source: OSB API")
elif source == "contact_form":
service_details.append(f"Source: Contact Form")
# Prepare lead name based on whether it's a service lead or generic contact
if hasattr(lead, "service") and lead.service:
lead_name = f"Servala - Interest in {lead.service.name}"
else:
lead_name = "Servala - Website Contact"
# Prepare lead data
lead_data = {
"name": f"Servala - Interest in {lead.service.name}",
"name": lead_name,
"contact_name": lead.name,
"partner_name": lead.company,
"partner_name": (
lead.company if hasattr(lead, "company") and lead.company else ""
),
"email_from": lead.email,
"phone": lead.phone,
"phone": lead.phone if hasattr(lead, "phone") and lead.phone else "",
"description": (
f"{lead.message}<br/><br/>" + "<br/>".join(service_details)
if lead.message
@ -111,29 +123,50 @@ class OdooAPI:
logger.info(f"Successfully created lead in Odoo with ID: {odoo_lead_id}")
# Post message in chatter
message_data = {
"body": f"""
<p>Thank you for your interest in the service <strong>{lead.service.name}</strong>.
We recorded the following information and will get back to you soon.</p><br/>
<p>Contact Details:</p>
<ul>
<li><strong>Name:</strong> {lead.name}</li>
<li><strong>Company:</strong> {lead.company}</li>
<li><strong>Email:</strong> {lead.email}</li>
<li><strong>Phone:</strong> {lead.phone}</li>
</ul>
if hasattr(lead, "service") and lead.service:
# For service-related leads
message_data = {
"body": f"""
<p>Thank you for your interest in the service <strong>{lead.service.name}</strong>.
We recorded the following information and will get back to you soon:</p><br/>
<p>Contact Details:</p>
<ul>
<li><strong>Name:</strong> {lead.name}</li>
<li><strong>Company:</strong> {lead.company if hasattr(lead, "company") and lead.company else "N/A"}</li>
<li><strong>Email:</strong> {lead.email}</li>
<li><strong>Phone:</strong> {lead.phone if hasattr(lead, "phone") and lead.phone else "N/A"}</li>
</ul>
<p>Service Details:<p>
<ul>
<li><strong>Service:</strong> {lead.service.name}</li>
{f'<li><strong>Provider:</strong> {provider_name}</li>' if provider_name else ''}
{f'<li><strong>Plan:</strong> {lead.plan.name}</li>' if lead.plan else ''}
</ul>
""",
"message_type": "comment",
"subtype_xmlid": "mail.mt_comment",
}
<p>Service Details:<p>
<ul>
<li><strong>Service:</strong> {lead.service.name}</li>
{f'<li><strong>Provider:</strong> {provider_name}</li>' if provider_name else ''}
{f'<li><strong>Plan:</strong> {lead.plan.name}</li>' if lead.plan else ''}
</ul>
""",
"message_type": "comment",
"subtype_xmlid": "mail.mt_comment",
}
else:
# For contact form submissions
message_data = {
"body": f"""
<p>Thank you for contacting Servala by VSHN.<br/>
We recorded the following information and will get back to you soon:</p><br/>
<p>Contact Details:</p>
<ul>
<li><strong>Name:</strong> {lead.name}</li>
<li><strong>Email:</strong> {lead.email}</li>
{f'<li><strong>Phone:</strong> {lead.phone}</li>' if lead.phone else ''}
{f'<li><strong>Company:</strong> {lead.company}</li>' if lead.company else ''}
{f'<li><strong>Message:</strong> {lead.message}</li>' if lead.message else ''}
</ul>
""",
"message_type": "comment",
"subtype_xmlid": "mail.mt_comment",
}
# Post the message
self.odoo.env["crm.lead"].browse(odoo_lead_id).message_post(

View file

@ -37,6 +37,9 @@
<li class="menu__item"><a class="menu__item-link" href="{% url 'services:provider_list' %}">Cloud Providers</a></li>
<li class="menu__item"><a class="menu__item-link" href="{% url 'services:partner_list' %}">Consulting Partners</a></li>
</ul>
<ul class="menu-cta mb-0">
<li class="mr-17"><a class="btn btn-outline-light btn-outline-primary" href="{% url 'services:contact' %}" role="button">Contact</a></li>
</ul>
</nav>
</div>
<div class="nav__toggle">

View file

@ -0,0 +1,82 @@
{% extends 'services/base.html' %}
{% load form_tags %}
{% block content %}
<div class="container py-5">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card shadow-sm">
<div class="card-body p-4">
<h2 class="mb-4">Contact Us</h2>
{% if messages %}
{% for message in messages %}
<div class="alert alert-{{ message.tags }}">
{{ message }}
</div>
{% endfor %}
{% endif %}
<form method="post">
{% csrf_token %}
<div class="mb-3">
<label for="{{ form.name.id_for_label }}" class="form-label">Your Name</label>
{{ form.name }}
{% if form.name.errors %}
<div class="invalid-feedback d-block">
{{ form.name.errors }}
</div>
{% endif %}
</div>
<div class="mb-3">
<label for="{{ form.email.id_for_label }}" class="form-label">Your Email Address</label>
{{ form.email }}
{% if form.email.errors %}
<div class="invalid-feedback d-block">
{{ form.email.errors }}
</div>
{% endif %}
</div>
<div class="mb-3">
<label for="{{ form.phone.id_for_label }}" class="form-label">Your Phone Number (Optional)</label>
{{ form.phone }}
{% if form.phone.errors %}
<div class="invalid-feedback d-block">
{{ form.phone.errors }}
</div>
{% endif %}
</div>
<div class="mb-3">
<label for="{{ form.company.id_for_label }}" class="form-label">Your Company (Optional)</label>
{{ form.company }}
{% if form.company.errors %}
<div class="invalid-feedback d-block">
{{ form.company.errors }}
</div>
{% endif %}
</div>
<div class="mb-3">
<label for="{{ form.message.id_for_label }}" class="form-label">Your Message (Optional)</label>
{{ form.message }}
{% if form.message.errors %}
<div class="invalid-feedback d-block">
{{ form.message.errors }}
</div>
{% endif %}
</div>
<div class="mt-4">
<button type="submit" class="btn btn-primary btn-lg">Send Message</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View file

@ -0,0 +1,18 @@
{% extends 'services/base.html' %}
{% block content %}
<div class="container py-5">
<div class="row justify-content-center">
<div class="col-md-8 text-center">
<div class="card shadow-sm">
<div class="card-body p-5">
<h2 class="mb-4">Thank You!</h2>
<p class="lead">Your message has been sent successfully.</p>
<p>We'll get back to you as soon as possible.</p>
<a href="{% url 'services:homepage' %}" class="btn btn-primary mt-3">Back to Home</a>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View file

@ -35,7 +35,7 @@
</div>
<div class="mb-40">
<label for="{{ form.phone.id_for_label }}" class="form-label text-purple">Your Phone Number</label>
<label for="{{ form.phone.id_for_label }}" class="form-label text-purple">Your Phone Number (Optional)</label>
{{ form.phone|addclass:"form-control" }}
{% if form.phone.errors %}
<div class="invalid-feedback d-block">
@ -45,7 +45,7 @@
</div>
<div class="mb-40">
<label for="{{ form.company.id_for_label }}" class="form-label text-purple">Your Company</label>
<label for="{{ form.company.id_for_label }}" class="form-label text-purple">Your Company (Optional)</label>
{{ form.company|addclass:"form-control" }}
{% if form.company.errors %}
<div class="invalid-feedback d-block">
@ -55,7 +55,7 @@
</div>
<div class="mb-40">
<label for="{{ form.message.id_for_label }}" class="form-label text-purple">Message (Optional)</label>
<label for="{{ form.message.id_for_label }}" class="form-label text-purple">Your Message (Optional)</label>
{{ form.message|addclass:"form-control" }}
{% if form.message.errors %}
<div class="invalid-feedback d-block">

View file

@ -15,4 +15,6 @@ urlpatterns = [
path("partner/<slug:slug>/", views.partner_detail, name="partner_detail"),
path("service/<slug:slug>/interest/", views.create_lead, name="create_lead"),
path("service/<slug:slug>/thank-you/", views.thank_you, name="thank_you"),
path("contact/", views.leads.contact, name="contact"),
path("contact/thank-you/", views.leads.contact_thank_you, name="contact_thank_you"),
]

View file

@ -91,3 +91,54 @@ def create_lead(request, slug):
def thank_you(request, slug):
service = get_object_or_404(Service, slug=slug)
return render(request, "services/thank_you.html", {"service": service})
def contact(request):
if request.method == "POST":
form = LeadForm(request.POST)
if form.is_valid():
# Create a minimal Lead object
from hub.services.models import Lead
lead = Lead(
name=form.cleaned_data["name"],
email=form.cleaned_data["email"],
message=form.cleaned_data["message"],
company=form.cleaned_data["company"],
phone=form.cleaned_data["phone"],
)
try:
logger.info(f"Attempting to create contact lead from {lead.name}")
odoo = OdooAPI()
odoo_lead_id = odoo.create_lead(lead, source="contact_form")
lead.odoo_lead_id = odoo_lead_id
lead.save()
logger.info(
f"Successfully created contact lead with Odoo ID: {odoo_lead_id}"
)
messages.success(
request, "Thank you for your message. We'll get back to you soon!"
)
return redirect("services:contact_thank_you")
except Exception as e:
logger.error(f"Failed to create contact lead: {str(e)}", exc_info=True)
error_message = "Sorry, there was an error processing your request. Please try again later."
if settings.DEBUG:
error_message += f" Error: {str(e)}"
messages.error(request, error_message)
else:
form = LeadForm()
context = {
"form": form,
}
return render(request, "services/contact_form.html", context)
def contact_thank_you(request):
return render(request, "services/contact_thank_you.html")