diff --git a/hub/services/forms.py b/hub/services/forms.py index 59af925..a608d44 100644 --- a/hub/services/forms.py +++ b/hub/services/forms.py @@ -13,13 +13,3 @@ class LeadForm(forms.ModelForm): "phone": forms.TextInput(attrs={"class": "form-control"}), "message": forms.Textarea(attrs={"class": "form-control", "rows": 4}), } - - -class PlanForm(forms.ModelForm): - class Meta: - model = Plan - fields = ("name", "description") - widgets = { - "description": forms.Textarea(attrs={"rows": 3}), - "features": forms.Textarea(attrs={"rows": 4}), - } diff --git a/hub/services/odoo.py b/hub/services/odoo.py index b25557f..52b6529 100644 --- a/hub/services/odoo.py +++ b/hub/services/odoo.py @@ -53,56 +53,21 @@ class OdooAPI: logger.debug("Full error details:", exc_info=True) raise - def create_lead(self, lead, source="form"): + def create_lead(self, lead, lead_title=""): """Create a lead in Odoo""" try: logger.info(f"Attempting to create lead for {lead.name}") - # Prepare service description - service_details = [] - - if hasattr(lead, "service") and lead.service: - service_details.append(f"Service: {lead.service.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": lead_name, + "name": "Servala" + lead_title, "contact_name": lead.name, "partner_name": ( lead.company if hasattr(lead, "company") and lead.company else "" ), "email_from": lead.email, "phone": lead.phone if hasattr(lead, "phone") and lead.phone else "", - "description": ( - f"{lead.message}

" + "
".join(service_details) - if lead.message - else "
".join(service_details) - ), + "description": lead.message, "type": "lead", "campaign_id": settings.ODOO_CONFIG["campaign_id"], "source_id": settings.ODOO_CONFIG["source_id"], @@ -122,60 +87,6 @@ class OdooAPI: odoo_lead_id = Lead.create(lead_data) logger.info(f"Successfully created lead in Odoo with ID: {odoo_lead_id}") - # Post message in chatter - if hasattr(lead, "service") and lead.service: - # For service-related leads - message_data = { - "body": f""" -

Thank you for your interest in the service {lead.service.name}. - We recorded the following information and will get back to you soon:


- -

Contact Details:

- - -

Service Details:

-

- """, - "message_type": "comment", - "subtype_xmlid": "mail.mt_comment", - } - else: - # For contact form submissions - message_data = { - "body": f""" -

Thank you for contacting Servala by VSHN.
- We recorded the following information and will get back to you soon:


- -

Contact Details:

- - """, - "message_type": "comment", - "subtype_xmlid": "mail.mt_comment", - } - - # Post the message - self.odoo.env["crm.lead"].browse(odoo_lead_id).message_post( - body=message_data["body"], - message_type=message_data["message_type"], - subtype_xmlid=message_data["subtype_xmlid"], - ) - - logger.info(f"Successfully posted message to lead {odoo_lead_id}") return odoo_lead_id except odoorpc.error.RPCError as e: diff --git a/hub/services/templates/services/contact_form.html b/hub/services/templates/services/contact_form.html index 8f5f26f..afd89f9 100644 --- a/hub/services/templates/services/contact_form.html +++ b/hub/services/templates/services/contact_form.html @@ -1,83 +1,24 @@ {% extends 'services/base.html' %} -{% load form_tags %} +{% load contact_tags %} {% block title %}Contact Us{% endblock %} {% block content %} +
+
+
+

Contact Us

+
+

We'd love to hear from you!

+
+
+
+
+
-
-
-

Contact Us

- - {% if messages %} - {% for message in messages %} -
- {{ message }} -
- {% endfor %} - {% endif %} - -
- {% csrf_token %} - -
- - {{ form.name }} - {% if form.name.errors %} -
- {{ form.name.errors }} -
- {% endif %} -
- -
- - {{ form.email }} - {% if form.email.errors %} -
- {{ form.email.errors }} -
- {% endif %} -
- -
- - {{ form.phone }} - {% if form.phone.errors %} -
- {{ form.phone.errors }} -
- {% endif %} -
- -
- - {{ form.company }} - {% if form.company.errors %} -
- {{ form.company.errors }} -
- {% endif %} -
- -
- - {{ form.message }} - {% if form.message.errors %} -
- {{ form.message.errors }} -
- {% endif %} -
- -
- -
-
-
-
+ {% embedded_contact_form source="Contact Us" %}
diff --git a/hub/services/templates/services/contact_thank_you.html b/hub/services/templates/services/contact_thank_you.html deleted file mode 100644 index 2e10d7d..0000000 --- a/hub/services/templates/services/contact_thank_you.html +++ /dev/null @@ -1,20 +0,0 @@ -{% extends 'services/base.html' %} - -{% block title %}Thanks{% endblock %} - -{% block content %} -
-
-
-
-
-

Thank You!

-

Your message has been sent successfully.

-

We'll get back to you as soon as possible.

- Back to Home -
-
-
-
-
-{% endblock %} \ No newline at end of file diff --git a/hub/services/templates/services/embedded_contact_form.html b/hub/services/templates/services/embedded_contact_form.html new file mode 100644 index 0000000..d0f719d --- /dev/null +++ b/hub/services/templates/services/embedded_contact_form.html @@ -0,0 +1,68 @@ +{% load form_tags %} + +
+
+
+ {% csrf_token %} + + {% if details %} + + {% endif %} + {% if service %} + + + {% endif %} + {% if offering %} + + + {% endif %} + {% if plan %} + + + {% endif %} + + +
+ + {{ form.name|addclass:"form-control" }} + {% if form.name.errors %} +
{{ form.name.errors }}
+ {% endif %} +
+ +
+ + {{ form.email|addclass:"form-control" }} + {% if form.email.errors %} +
{{ form.email.errors }}
+ {% endif %} +
+ +
+ + {{ form.phone|addclass:"form-control" }} + {% if form.phone.errors %} +
{{ form.phone.errors }}
+ {% endif %} +
+ +
+ + {{ form.company|addclass:"form-control" }} + {% if form.company.errors %} +
{{ form.company.errors }}
+ {% endif %} +
+ +
+ + {{ form.message|addclass:"form-control" }} + {% if form.message.errors %} +
{{ form.message.errors }}
+ {% endif %} +
+ + +
+
+
\ No newline at end of file diff --git a/hub/services/templates/services/offering_detail.html b/hub/services/templates/services/offering_detail.html index 801c47f..9fbd3e0 100644 --- a/hub/services/templates/services/offering_detail.html +++ b/hub/services/templates/services/offering_detail.html @@ -150,19 +150,19 @@ {% endif %}
- - Order Now - +

Order This Plan

+ {% load contact_tags %} + {% embedded_contact_form source="Plan Order" service=offering.service offering_id=offering.id plan_id=plan.id %}
- {% empty %} + {% empty %}

No plans available yet.

- I'm interested in a plan +

I'm interested in this offering

+ {% load contact_tags %} + {% embedded_contact_form source="Offering Interest" service=offering.service offering_id=offering.id %}
{% endfor %} diff --git a/hub/services/templates/services/partner_detail.html b/hub/services/templates/services/partner_detail.html index da5be3e..c65e4c6 100644 --- a/hub/services/templates/services/partner_detail.html +++ b/hub/services/templates/services/partner_detail.html @@ -1,4 +1,5 @@ {% extends 'services/base.html' %} +{% load contact_tags %} {% block title %}Consulting Partner {{ partner.name }}{% endblock %} @@ -177,6 +178,18 @@ {% endif %} + + + +
+

Contact

+
+
+ {% embedded_contact_form source="Partner Page" details=partner.name %} +
+
+
+ diff --git a/hub/services/templates/services/partner_list.html b/hub/services/templates/services/partner_list.html index f0ce150..edb8259 100644 --- a/hub/services/templates/services/partner_list.html +++ b/hub/services/templates/services/partner_list.html @@ -1,4 +1,6 @@ {% extends 'services/base.html' %} +{% load static %} +{% load contact_tags %} {% block title %}Consulting Partners{% endblock %} @@ -162,4 +164,27 @@ + +
+
+
+
+ +
+
+
+

Missing a Consulting Partner?

+
+

You miss a consulting partner on this list? Let us know which one and we'll get in touch with you!

+
+
+ {% embedded_contact_form source="Missing Consulting Partner" %} +
+
+
+
+
+
{% endblock %} \ No newline at end of file diff --git a/hub/services/templates/services/provider_detail.html b/hub/services/templates/services/provider_detail.html index 880ce4f..d9d86a2 100644 --- a/hub/services/templates/services/provider_detail.html +++ b/hub/services/templates/services/provider_detail.html @@ -1,4 +1,5 @@ {% extends 'services/base.html' %} +{% load contact_tags %} {% block title %}Service Provider {{ provider.name }}{% endblock %} @@ -177,6 +178,18 @@ {% endif %} + + +
+

Contact

+

Do you miss a service on this cloud provider? Do you have any questions about this cloud provider? We're here to help!

+
+
+ {% embedded_contact_form source="Provider Page" details=provider.name %} +
+
+
+ diff --git a/hub/services/templates/services/provider_list.html b/hub/services/templates/services/provider_list.html index 30c31ba..ac752c1 100644 --- a/hub/services/templates/services/provider_list.html +++ b/hub/services/templates/services/provider_list.html @@ -1,4 +1,6 @@ {% extends 'services/base.html' %} +{% load static %} +{% load contact_tags %} {% block title %}Service Providers{% endblock %} @@ -128,4 +130,27 @@ + +
+
+
+
+ +
+
+
+

Missing a Cloud Provider?

+
+

You miss a cloud provider on this list? Let us know which one and we'll get in touch with you!

+
+
+ {% embedded_contact_form source="Missing Cloud Provider" %} +
+
+
+
+
+
{% endblock %} \ No newline at end of file diff --git a/hub/services/templates/services/service_detail.html b/hub/services/templates/services/service_detail.html index c07500d..a68433a 100644 --- a/hub/services/templates/services/service_detail.html +++ b/hub/services/templates/services/service_detail.html @@ -129,19 +129,24 @@
- {% if service.is_coming_soon %} - I'm interested in this service - {% elif service.offerings.exists %} -

Get it on

-

Choose one of our trusted service providers

+ {% if service.offerings.exists %} +

Get it on

+

Choose one of our trusted service providers

{% for offering in service.offerings.all %} -

{{ offering.cloud_provider.name }}

+

{{ offering.cloud_provider.name }}

{% endfor %} {% else %} - I'm interested in this service +
+

Contact Us About This Service

+
+
+ {% load contact_tags %} + {% embedded_contact_form source="Service Detail" service=service %} +
+
+
{% endif %}
diff --git a/hub/services/templates/services/service_list.html b/hub/services/templates/services/service_list.html index 8361bba..126ea8e 100644 --- a/hub/services/templates/services/service_list.html +++ b/hub/services/templates/services/service_list.html @@ -1,5 +1,6 @@ {% extends 'services/base.html' %} {% load static %} +{% load contact_tags %} {% block title %}Services{% endblock %} @@ -185,29 +186,33 @@ {% endfor %} -
-
-
-
- - missing service logo - -
-
-
- -
-

Your favorite service is missing? Let us know which one!

-
-
-
-
+ +
+
+
+
+ +
+
+
+

Missing a Service?

+
+

You miss a service on this list? Let us know which one and we'll get in touch with you!

+
+
+ {% embedded_contact_form source="Missing Service" %} +
+
+
+
+
+
{% endblock %} \ No newline at end of file diff --git a/hub/services/templates/services/thank_you.html b/hub/services/templates/services/thank_you.html index 1f576e1..7ab96d4 100644 --- a/hub/services/templates/services/thank_you.html +++ b/hub/services/templates/services/thank_you.html @@ -3,42 +3,18 @@ {% block title %}Thanks{% endblock %} {% block content %} -
-
-
-
-
-
-
- - - - - - - - - - - - - -
-
-

Inquiry received successfully!

-
-

Thank you for your interest in {{ service.name }}. We have received your inquiry and our team will contact you shortly. A confirmation email will be sent to your provided email address.

-
-
-
+
+
+
+
+
+

Thank You!

+

Your message has been sent successfully.

+

We'll get back to you as soon as possible.

+ Take me home
-
+ {% endblock %} \ No newline at end of file diff --git a/hub/services/templatetags/contact_tags.py b/hub/services/templatetags/contact_tags.py new file mode 100644 index 0000000..748a2cb --- /dev/null +++ b/hub/services/templatetags/contact_tags.py @@ -0,0 +1,59 @@ +# hub/services/templatetags/contact_tags.py +from django import template +from hub.services.forms import LeadForm +from hub.services.models import Service, ServiceOffering, Plan + +register = template.Library() + + +@register.inclusion_tag("services/embedded_contact_form.html", takes_context=True) +def embedded_contact_form( + context, source=None, details=None, service=None, offering_id=None, plan_id=None +): + """ + Renders an embedded contact form with optional service context information. + + Usage: + {% load contact_tags %} + {% embedded_contact_form source="Partner Page" details="ACME Corp" %} + {% embedded_contact_form service=service offering_id=offering.id plan_id=plan.id %} + """ + request = context["request"] + form = LeadForm() + + service_obj = None + offering_obj = None + plan_obj = None + + # Resolve service/offering/plan objects if IDs provided + if service and isinstance(service, str): + try: + service_obj = Service.objects.get(slug=service) + except Service.DoesNotExist: + pass + elif service: + service_obj = service + + if offering_id and service_obj: + try: + offering_obj = ServiceOffering.objects.get( + id=offering_id, service=service_obj + ) + except ServiceOffering.DoesNotExist: + pass + + if plan_id and offering_obj: + try: + plan_obj = Plan.objects.get(id=plan_id, offering=offering_obj) + except Plan.DoesNotExist: + pass + + return { + "form": form, + "source": source, + "details": details, + "service": service_obj, + "offering": offering_obj, + "plan": plan_obj, + "request": request, + } diff --git a/hub/services/urls.py b/hub/services/urls.py index 6de669f..008550e 100644 --- a/hub/services/urls.py +++ b/hub/services/urls.py @@ -17,8 +17,7 @@ urlpatterns = [ ), path("provider//", views.provider_detail, name="provider_detail"), path("partner//", views.partner_detail, name="partner_detail"), - path("service//interest/", views.create_lead, name="create_lead"), - path("service//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"), + path("contact/thank-you/", views.thank_you, name="thank_you"), + path("contact-form/", views.contact_form, name="contact_form"), ] diff --git a/hub/services/views/leads.py b/hub/services/views/leads.py index 205c54e..72108b4 100644 --- a/hub/services/views/leads.py +++ b/hub/services/views/leads.py @@ -1,107 +1,28 @@ import logging -from django.conf import settings -from django.shortcuts import render, get_object_or_404, redirect +from django.shortcuts import render, redirect from django.contrib import messages -from django.urls import reverse -from hub.services.models import ( - Service, - ServiceOffering, - Plan, -) + from hub.services.forms import LeadForm from hub.services.odoo import OdooAPI logger = logging.getLogger(__name__) -def create_lead(request, slug): - service = get_object_or_404( - Service.objects.prefetch_related("categories"), slug=slug - ) - selected_offering = None - selected_plan = None - - # Get the offering if specified - if request.GET.get("offering"): - selected_offering = get_object_or_404( - ServiceOffering.objects.select_related("cloud_provider").prefetch_related( - "plans" - ), - id=request.GET.get("offering"), - service=service, - ) - - if selected_offering.plans.exists(): - if not request.GET.get("plan"): - # If there's only one plan, automatically select it - if selected_offering.plans.count() == 1: - return redirect( - f"{reverse('services:create_lead', kwargs={'slug': service.slug})}?offering={selected_offering.id}&plan={selected_offering.plans.first().id}" - ) - # If there are multiple plans, redirect to offering detail - return redirect( - "services:offering_detail", - provider_slug=selected_offering.cloud_provider.slug, - service_slug=selected_offering.service.slug, - ) - - # Get the selected plan - selected_plan = get_object_or_404( - Plan, - id=request.GET.get("plan"), - offering=selected_offering, - ) - - if request.method == "POST": - form = LeadForm(request.POST) - if form.is_valid(): - lead = form.save(commit=False) - lead.service = service - lead.offering = selected_offering - lead.plan = selected_plan - - try: - logger.info(f"Attempting to create lead for service: {service.name}") - odoo = OdooAPI() - odoo_lead_id = odoo.create_lead(lead) - lead.odoo_lead_id = odoo_lead_id - lead.save() - - logger.info(f"Successfully created lead with Odoo ID: {odoo_lead_id}") - return redirect("services:thank_you", slug=service.slug) - - except Exception as e: - logger.error(f"Failed to create 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, - "service": service, - "selected_offering": selected_offering, - "selected_plan": selected_plan, - } - return render(request, "services/lead_form.html", context) - - -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): + return render(request, "services/contact_form.html") + + +def thank_you(request): + return render(request, "services/thank_you.html") + + +def contact_form(request): if request.method == "POST": form = LeadForm(request.POST) if form.is_valid(): - # Create a minimal Lead object - from hub.services.models import Lead + from hub.services.models import Lead, Service, ServiceOffering, Plan + # Create a lead with context information lead = Lead( name=form.cleaned_data["name"], email=form.cleaned_data["email"], @@ -110,37 +31,106 @@ def contact(request): phone=form.cleaned_data["phone"], ) + # Store the source/context information + source = request.POST.get("source", "Contact Form") + details = request.POST.get("details", "") + next_url = request.POST.get("next", "/") + + # Handle service/offering/plan data + service_id = request.POST.get("service_id") + service_name = request.POST.get("service_name", "") + offering_id = request.POST.get("offering_id") + offering_name = request.POST.get("offering_name", "") + plan_id = request.POST.get("plan_id") + plan_name = request.POST.get("plan_name", "") + + # Link to related objects if they exist + if service_id: + try: + lead.service = Service.objects.get(id=service_id) + except Service.DoesNotExist: + pass + + if offering_id: + try: + lead.offering = ServiceOffering.objects.get(id=offering_id) + except ServiceOffering.DoesNotExist: + pass + + if plan_id: + try: + lead.plan = Plan.objects.get(id=plan_id) + except Plan.DoesNotExist: + pass + + # Add context to the message and lead_title + lead_title = "" + context_info = [] + + if source: + context_info.append(f"Source Page: {source}") + lead_title += f" - {source}" + + if details: + context_info.append(f"Details: {details}") + lead_title += f" - {details}" + + # Add service information to lead title and message + service_info = [] + if service_name: + service_info.append(f"Service: {service_name}") + lead_title += f" - {service_name}" + + if offering_name: + service_info.append(f"Provider: {offering_name}") + + if plan_name: + service_info.append(f"Plan: {plan_name}") + + if service_info: + context_info.append("Service Information: " + ", ".join(service_info)) + + # Format the final message with all context + formatted_context = "
".join(context_info) + lead.message = ( + lead.message + "

" + formatted_context + if lead.message + else formatted_context + ) + try: - logger.info(f"Attempting to create contact lead from {lead.name}") + logger.info( + f"Contact form submission for {service_name or 'general inquiry'}" + ) odoo = OdooAPI() - odoo_lead_id = odoo.create_lead(lead, source="contact_form") + odoo_lead_id = odoo.create_lead(lead, lead_title) 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") + logger.info(f"Successfully created lead with Odoo ID: {odoo_lead_id}") + + # Redirect to thank you page + return redirect("services: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." + logger.error(f"Failed to create lead: {str(e)}", exc_info=True) + messages.error( + request, + "Sorry, there was an error processing your request. Please try again later.", + ) + return redirect(next_url) + else: + # Return form with errors + return render( + request, + "services/contact_form.html", + { + "form": form, + "source": request.POST.get("source", ""), + "details": request.POST.get("details", ""), + }, + ) - 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") + return redirect( + "services:homepage" + ) # Redirect if someone tries to access the URL directly