update on the lead & opportunity
This commit is contained in:
parent
cca37be3b3
commit
2ee9a86720
10
.prettierrc
Normal file
10
.prettierrc
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"printWidth": 80,
|
||||||
|
"tabWidth": 4,
|
||||||
|
"useTabs": false,
|
||||||
|
"semi": true,
|
||||||
|
"singleQuote": true,
|
||||||
|
"trailingComma": "es5",
|
||||||
|
"bracketSpacing": true,
|
||||||
|
"arrowParens": "always"
|
||||||
|
}
|
||||||
@ -50,7 +50,8 @@ from .models import (
|
|||||||
CarMake,
|
CarMake,
|
||||||
Customer,
|
Customer,
|
||||||
Organization,
|
Organization,
|
||||||
DealerSettings
|
DealerSettings,
|
||||||
|
Tasks
|
||||||
)
|
)
|
||||||
from django_ledger import models as ledger_models
|
from django_ledger import models as ledger_models
|
||||||
from django.forms import (
|
from django.forms import (
|
||||||
@ -1120,6 +1121,7 @@ class ActivityForm(forms.ModelForm):
|
|||||||
associated with the form and the fields it comprises.
|
associated with the form and the fields it comprises.
|
||||||
:type Meta: type
|
:type Meta: type
|
||||||
"""
|
"""
|
||||||
|
activity_type = forms.ChoiceField(choices=[("call", "Call"), ("email", "Email"), ("meeting", "Meeting")])
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Activity
|
model = Activity
|
||||||
fields = ["activity_type", "notes"]
|
fields = ["activity_type", "notes"]
|
||||||
@ -1140,9 +1142,34 @@ class OpportunityForm(forms.ModelForm):
|
|||||||
:ivar Meta.fields: List of fields from the model included in the form.
|
:ivar Meta.fields: List of fields from the model included in the form.
|
||||||
:type Meta.fields: list
|
:type Meta.fields: list
|
||||||
"""
|
"""
|
||||||
|
closing_date = forms.DateField(
|
||||||
|
label=_("Expected Closing Date"),
|
||||||
|
widget=forms.DateInput(attrs={"type": "date"})
|
||||||
|
)
|
||||||
|
|
||||||
|
probability = forms.IntegerField(
|
||||||
|
label=_("Probability (%)"),
|
||||||
|
widget=forms.NumberInput(attrs={
|
||||||
|
'type': 'range',
|
||||||
|
'min': '0',
|
||||||
|
'max': '100',
|
||||||
|
'step': '1',
|
||||||
|
'class': 'form-range',
|
||||||
|
'oninput': 'this.nextElementSibling.value = this.value'
|
||||||
|
}),
|
||||||
|
initial=50 # Default value
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Opportunity
|
model = Opportunity
|
||||||
fields = ["customer", "car", "stage", "probability", "staff", "closing_date"]
|
fields = ["lead", "car", "stage", "probability", "expected_revenue", "closing_date"]
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
# Add a visible number input to display the current value
|
||||||
|
self.fields['probability'].widget.attrs['class'] = 'd-none' # Hide the default input
|
||||||
|
if self.instance and self.instance.pk:
|
||||||
|
self.fields['probability'].initial = self.instance.probability
|
||||||
|
|
||||||
|
|
||||||
class InvoiceModelCreateForm(InvoiceModelCreateFormBase):
|
class InvoiceModelCreateForm(InvoiceModelCreateFormBase):
|
||||||
@ -1684,3 +1711,33 @@ class PaymentPlanForm(forms.Form):
|
|||||||
self.fields['first_name'].initial = user.first_name
|
self.fields['first_name'].initial = user.first_name
|
||||||
self.fields['last_name'].initial = user.last_name
|
self.fields['last_name'].initial = user.last_name
|
||||||
self.fields['email'].initial = user.email
|
self.fields['email'].initial = user.email
|
||||||
|
|
||||||
|
|
||||||
|
# class ActivityHistoryForm(forms.Form):
|
||||||
|
# activity_type = forms.ChoiceField(
|
||||||
|
# choices=[
|
||||||
|
# ('note', 'Note'),
|
||||||
|
# ('call', 'Call'),
|
||||||
|
# ('email', 'Email'),
|
||||||
|
# ('meeting', 'Meeting'),],
|
||||||
|
# widget=forms.Select(attrs={
|
||||||
|
# 'class': 'form-control',
|
||||||
|
# 'id': 'activity-type'
|
||||||
|
# }),
|
||||||
|
# label=_('Activity Type')
|
||||||
|
# )
|
||||||
|
# description = forms.CharField(
|
||||||
|
# widget=forms.Textarea(attrs={
|
||||||
|
# 'class': 'form-control',
|
||||||
|
# 'id': 'activity-description'
|
||||||
|
# }),
|
||||||
|
# label=_('Description')
|
||||||
|
# )
|
||||||
|
|
||||||
|
class StaffTaskForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = Tasks
|
||||||
|
fields = ['title','due_date' ,'description']
|
||||||
|
widgets = {
|
||||||
|
'due_date': forms.DateTimeInput(attrs={'type': 'date'}),
|
||||||
|
}
|
||||||
@ -0,0 +1,44 @@
|
|||||||
|
# Generated by Django 5.1.7 on 2025-05-13 15:19
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('contenttypes', '0002_remove_content_type_name'),
|
||||||
|
('inventory', '0017_alter_activity_activity_type'),
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='opportunity',
|
||||||
|
name='closed',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='opportunity',
|
||||||
|
name='status',
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Tasks',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('object_id', models.UUIDField()),
|
||||||
|
('title', models.CharField(max_length=255, verbose_name='Title')),
|
||||||
|
('description', models.TextField(blank=True, null=True, verbose_name='Description')),
|
||||||
|
('due_date', models.DateField(verbose_name='Due Date')),
|
||||||
|
('created', models.DateTimeField(auto_now_add=True, verbose_name='Created')),
|
||||||
|
('updated', models.DateTimeField(auto_now=True, verbose_name='Updated')),
|
||||||
|
('assigned_to', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='tasks_assigned', to=settings.AUTH_USER_MODEL)),
|
||||||
|
('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype')),
|
||||||
|
('created_by', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, related_name='tasks_created', to=settings.AUTH_USER_MODEL)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Task',
|
||||||
|
'verbose_name_plural': 'Tasks',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
20
inventory/migrations/0019_tasks_dealer.py
Normal file
20
inventory/migrations/0019_tasks_dealer.py
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# Generated by Django 5.1.7 on 2025-05-13 16:22
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('inventory', '0018_remove_opportunity_closed_remove_opportunity_status_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='tasks',
|
||||||
|
name='dealer',
|
||||||
|
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, related_name='tasks', to='inventory.dealer'),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
]
|
||||||
18
inventory/migrations/0020_tasks_completed.py
Normal file
18
inventory/migrations/0020_tasks_completed.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.1.7 on 2025-05-13 16:57
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('inventory', '0019_tasks_dealer'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='tasks',
|
||||||
|
name='completed',
|
||||||
|
field=models.BooleanField(default=False, verbose_name='Completed'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
# Generated by Django 5.1.7 on 2025-05-14 10:29
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('inventory', '0020_tasks_completed'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='lead',
|
||||||
|
name='status',
|
||||||
|
field=models.CharField(choices=[('new', 'New'), ('follow_up', 'Follow-up'), ('negotiation', 'Negotiation'), ('won', 'Won'), ('lost', 'Lost'), ('closed', 'Closed')], db_index=True, default='new', max_length=50, verbose_name='Status'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='leadstatushistory',
|
||||||
|
name='new_status',
|
||||||
|
field=models.CharField(choices=[('new', 'New'), ('follow_up', 'Follow-up'), ('negotiation', 'Negotiation'), ('won', 'Won'), ('lost', 'Lost'), ('closed', 'Closed')], max_length=50, verbose_name='New Status'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='leadstatushistory',
|
||||||
|
name='old_status',
|
||||||
|
field=models.CharField(choices=[('new', 'New'), ('follow_up', 'Follow-up'), ('negotiation', 'Negotiation'), ('won', 'Won'), ('lost', 'Lost'), ('closed', 'Closed')], max_length=50, verbose_name='Old Status'),
|
||||||
|
),
|
||||||
|
]
|
||||||
19
inventory/migrations/0022_opportunity_expected_revenue.py
Normal file
19
inventory/migrations/0022_opportunity_expected_revenue.py
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# Generated by Django 5.1.7 on 2025-05-14 10:41
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('inventory', '0021_alter_lead_status_alter_leadstatushistory_new_status_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='opportunity',
|
||||||
|
name='expected_revenue',
|
||||||
|
field=models.DecimalField(decimal_places=2, default=0, max_digits=10, verbose_name='Expected Revenue'),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
]
|
||||||
18
inventory/migrations/0023_alter_opportunity_stage.py
Normal file
18
inventory/migrations/0023_alter_opportunity_stage.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.1.7 on 2025-05-14 10:58
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('inventory', '0022_opportunity_expected_revenue'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='opportunity',
|
||||||
|
name='stage',
|
||||||
|
field=models.CharField(choices=[('discovery', 'Discovery'), ('proposal', 'Proposal'), ('negotiation', 'Negotiation'), ('closed_won', 'Closed Won'), ('closed_lost', 'Closed Lost')], max_length=20, verbose_name='Stage'),
|
||||||
|
),
|
||||||
|
]
|
||||||
20
inventory/migrations/0024_alter_opportunity_customer.py
Normal file
20
inventory/migrations/0024_alter_opportunity_customer.py
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# Generated by Django 5.1.7 on 2025-05-14 10:59
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('django_ledger', '0021_alter_bankaccountmodel_account_model_and_more'),
|
||||||
|
('inventory', '0023_alter_opportunity_stage'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='opportunity',
|
||||||
|
name='customer',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='opportunities', to='django_ledger.customermodel'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -973,9 +973,9 @@ class Channel(models.TextChoices):
|
|||||||
|
|
||||||
class Status(models.TextChoices):
|
class Status(models.TextChoices):
|
||||||
NEW = "new", _("New")
|
NEW = "new", _("New")
|
||||||
FOLLOW_UP = "follow_up", _("Needs Follow-up")
|
FOLLOW_UP = "follow_up", _("Follow-up")
|
||||||
NEGOTIATION = "negotiation", _("Under Negotiation")
|
NEGOTIATION = "negotiation", _("Negotiation")
|
||||||
WON = "won", _("Converted")
|
WON = "won", _("Won")
|
||||||
LOST = "lost", _("Lost")
|
LOST = "lost", _("Lost")
|
||||||
CLOSED = "closed", _("Closed")
|
CLOSED = "closed", _("Closed")
|
||||||
|
|
||||||
@ -1020,7 +1020,7 @@ class ActionChoices(models.TextChoices):
|
|||||||
|
|
||||||
|
|
||||||
class Stage(models.TextChoices):
|
class Stage(models.TextChoices):
|
||||||
PROSPECT = "prospect", _("Prospect")
|
DISCOVERY = "discovery", _("Discovery")
|
||||||
PROPOSAL = "proposal", _("Proposal")
|
PROPOSAL = "proposal", _("Proposal")
|
||||||
NEGOTIATION = "negotiation", _("Negotiation")
|
NEGOTIATION = "negotiation", _("Negotiation")
|
||||||
CLOSED_WON = "closed_won", _("Closed Won")
|
CLOSED_WON = "closed_won", _("Closed Won")
|
||||||
@ -1515,7 +1515,7 @@ class Opportunity(models.Model):
|
|||||||
Dealer, on_delete=models.CASCADE, related_name="opportunities"
|
Dealer, on_delete=models.CASCADE, related_name="opportunities"
|
||||||
)
|
)
|
||||||
customer = models.ForeignKey(
|
customer = models.ForeignKey(
|
||||||
CustomerModel, on_delete=models.CASCADE, related_name="opportunities"
|
CustomerModel, on_delete=models.CASCADE, related_name="opportunities",null=True,blank=True
|
||||||
)
|
)
|
||||||
car = models.ForeignKey(
|
car = models.ForeignKey(
|
||||||
Car, on_delete=models.SET_NULL, null=True, blank=True, verbose_name=_("Car")
|
Car, on_delete=models.SET_NULL, null=True, blank=True, verbose_name=_("Car")
|
||||||
@ -1523,12 +1523,6 @@ class Opportunity(models.Model):
|
|||||||
stage = models.CharField(
|
stage = models.CharField(
|
||||||
max_length=20, choices=Stage.choices, verbose_name=_("Stage")
|
max_length=20, choices=Stage.choices, verbose_name=_("Stage")
|
||||||
)
|
)
|
||||||
status = models.CharField(
|
|
||||||
max_length=20,
|
|
||||||
choices=Status.choices,
|
|
||||||
verbose_name=_("Status"),
|
|
||||||
default=Status.NEW,
|
|
||||||
)
|
|
||||||
staff = models.ForeignKey(
|
staff = models.ForeignKey(
|
||||||
Staff,
|
Staff,
|
||||||
on_delete=models.SET_NULL,
|
on_delete=models.SET_NULL,
|
||||||
@ -1538,10 +1532,12 @@ class Opportunity(models.Model):
|
|||||||
)
|
)
|
||||||
lead = models.OneToOneField("Lead",related_name="opportunity", on_delete=models.CASCADE,null=True,blank=True)
|
lead = models.OneToOneField("Lead",related_name="opportunity", on_delete=models.CASCADE,null=True,blank=True)
|
||||||
probability = models.PositiveIntegerField(validators=[validate_probability])
|
probability = models.PositiveIntegerField(validators=[validate_probability])
|
||||||
|
expected_revenue = models.DecimalField(
|
||||||
|
max_digits=10, decimal_places=2, verbose_name=_("Expected Revenue")
|
||||||
|
)
|
||||||
closing_date = models.DateField(verbose_name=_("Closing Date"),null=True,blank=True)
|
closing_date = models.DateField(verbose_name=_("Closing Date"),null=True,blank=True)
|
||||||
created = models.DateTimeField(auto_now_add=True, verbose_name=_("Created"))
|
created = models.DateTimeField(auto_now_add=True, verbose_name=_("Created"))
|
||||||
updated = models.DateTimeField(auto_now=True, verbose_name=_("Updated"))
|
updated = models.DateTimeField(auto_now=True, verbose_name=_("Updated"))
|
||||||
closed = models.BooleanField(default=False, verbose_name=_("Closed"))
|
|
||||||
estimate = models.OneToOneField(EstimateModel, related_name="opportunity",on_delete=models.SET_NULL,null=True,blank=True)
|
estimate = models.OneToOneField(EstimateModel, related_name="opportunity",on_delete=models.SET_NULL,null=True,blank=True)
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("Opportunity")
|
verbose_name = _("Opportunity")
|
||||||
@ -1569,6 +1565,31 @@ class Notes(models.Model):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"Note by {self.created_by.first_name} on {self.content_object}"
|
return f"Note by {self.created_by.first_name} on {self.content_object}"
|
||||||
|
|
||||||
|
class Tasks(models.Model):
|
||||||
|
dealer = models.ForeignKey(Dealer, on_delete=models.CASCADE, related_name="tasks")
|
||||||
|
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
|
||||||
|
object_id = models.UUIDField()
|
||||||
|
content_object = GenericForeignKey("content_type", "object_id")
|
||||||
|
title = models.CharField(max_length=255, verbose_name=_("Title"))
|
||||||
|
description = models.TextField(verbose_name=_("Description"),null=True,blank=True)
|
||||||
|
due_date = models.DateField(verbose_name=_("Due Date"))
|
||||||
|
completed = models.BooleanField(default=False, verbose_name=_("Completed"))
|
||||||
|
assigned_to = models.ForeignKey(
|
||||||
|
User, on_delete=models.DO_NOTHING, related_name="tasks_assigned",null=True,blank=True
|
||||||
|
)
|
||||||
|
created_by = models.ForeignKey(
|
||||||
|
User, on_delete=models.DO_NOTHING, related_name="tasks_created"
|
||||||
|
)
|
||||||
|
created = models.DateTimeField(auto_now_add=True, verbose_name=_("Created"))
|
||||||
|
updated = models.DateTimeField(auto_now=True, verbose_name=_("Updated"))
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _("Task")
|
||||||
|
verbose_name_plural = _("Tasks")
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"Task by {self.created_by.email} on {self.content_object}"
|
||||||
|
|
||||||
class Email(models.Model):
|
class Email(models.Model):
|
||||||
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
|
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
|
||||||
object_id = models.UUIDField()
|
object_id = models.UUIDField()
|
||||||
|
|||||||
@ -117,8 +117,18 @@ urlpatterns = [
|
|||||||
path('crm/leads/<int:pk>/update-note/', views.update_note, name='update_note_to_lead'),
|
path('crm/leads/<int:pk>/update-note/', views.update_note, name='update_note_to_lead'),
|
||||||
path("crm/leads/<int:pk>/delete-note/", views.delete_note, name="delete_note_to_lead"),
|
path("crm/leads/<int:pk>/delete-note/", views.delete_note, name="delete_note_to_lead"),
|
||||||
path(
|
path(
|
||||||
"crm/leads/<int:pk>/add-activity/",
|
"crm/<int:pk>/update-task/",
|
||||||
views.add_activity_to_lead,
|
views.update_task,
|
||||||
|
name="update_task",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"crm/<str:content_type>/<int:pk>/add-task/",
|
||||||
|
views.add_task,
|
||||||
|
name="add_task",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"crm/<str:content_type>/<int:pk>/add-activity/",
|
||||||
|
views.add_activity,
|
||||||
name="add_activity",
|
name="add_activity",
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
|
|||||||
@ -1362,6 +1362,6 @@ def handle_payment(request,order):
|
|||||||
return transaction_url
|
return transaction_url
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# def get_user_quota(user):
|
# def get_user_quota(user):
|
||||||
# return user.dealer.quota
|
# return user.dealer.quota
|
||||||
|
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import numpy as np
|
|||||||
# from rich import print
|
# from rich import print
|
||||||
from random import randint
|
from random import randint
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
from django.apps import apps
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from calendar import month_name
|
from calendar import month_name
|
||||||
from pyzbar.pyzbar import decode
|
from pyzbar.pyzbar import decode
|
||||||
@ -24,7 +25,7 @@ from django.conf import settings
|
|||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from django.db.models import Func
|
from django.db.models import Func
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.http import JsonResponse, HttpResponseForbidden
|
from django.http import Http404, JsonResponse, HttpResponseForbidden
|
||||||
from django.forms import HiddenInput, ValidationError
|
from django.forms import HiddenInput, ValidationError
|
||||||
from django.shortcuts import HttpResponse
|
from django.shortcuts import HttpResponse
|
||||||
from django.db.models import Sum, F, Count
|
from django.db.models import Sum, F, Count
|
||||||
@ -4580,10 +4581,15 @@ class LeadDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
|
|||||||
context["activities"] = models.Activity.objects.filter(
|
context["activities"] = models.Activity.objects.filter(
|
||||||
content_type__model="lead", object_id=self.object.id
|
content_type__model="lead", object_id=self.object.id
|
||||||
)
|
)
|
||||||
|
context["tasks"] = models.Tasks.objects.filter(
|
||||||
|
content_type__model="lead", object_id=self.object.id
|
||||||
|
)
|
||||||
context["status_history"] = models.LeadStatusHistory.objects.filter(
|
context["status_history"] = models.LeadStatusHistory.objects.filter(
|
||||||
lead=self.object
|
lead=self.object
|
||||||
)
|
)
|
||||||
context["transfer_form"] = forms.LeadTransferForm()
|
context["transfer_form"] = forms.LeadTransferForm()
|
||||||
|
context["activity_form"] = forms.ActivityForm()
|
||||||
|
context["staff_task_form"] = forms.StaffTaskForm()
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
@ -4673,10 +4679,10 @@ def lead_create(request):
|
|||||||
|
|
||||||
def lead_tracking(request):
|
def lead_tracking(request):
|
||||||
dealer = get_user_type(request)
|
dealer = get_user_type(request)
|
||||||
new = models.Lead.objects.filter(dealer=dealer)
|
new = models.Lead.objects.filter(dealer=dealer, status="new")
|
||||||
follow_up = models.Lead.objects.filter(dealer=dealer, next_action__in=["call", "meeting"])
|
follow_up = models.Lead.objects.filter(dealer=dealer, next_action__in=["call", "meeting"])
|
||||||
won = models.Lead.objects.filter(dealer=dealer, status="won")
|
won = models.Lead.objects.filter(dealer=dealer, status="won")
|
||||||
lose = models.Lead.objects.filter(dealer=dealer, status="lose")
|
lose = models.Lead.objects.filter(dealer=dealer, status="lost")
|
||||||
negotiation = models.Lead.objects.filter(dealer=dealer, status="negotiation")
|
negotiation = models.Lead.objects.filter(dealer=dealer, status="negotiation")
|
||||||
context = {"new": new,"follow_up": follow_up,"won": won,"lose": lose,"negotiation": negotiation}
|
context = {"new": new,"follow_up": follow_up,"won": won,"lose": lose,"negotiation": negotiation}
|
||||||
return render(request, "crm/leads/lead_tracking.html", context)
|
return render(request, "crm/leads/lead_tracking.html", context)
|
||||||
@ -4687,23 +4693,23 @@ def update_lead_actions(request):
|
|||||||
lead_id = request.POST.get('lead_id')
|
lead_id = request.POST.get('lead_id')
|
||||||
current_action = request.POST.get('current_action')
|
current_action = request.POST.get('current_action')
|
||||||
next_action = request.POST.get('next_action')
|
next_action = request.POST.get('next_action')
|
||||||
next_action_date = request.POST.get('next_action_date')
|
next_action_date = request.POST.get('next_action_date',None)
|
||||||
action_notes = request.POST.get('action_notes', '')
|
action_notes = request.POST.get('action_notes', '')
|
||||||
|
|
||||||
# Validate required fields
|
# Validate required fields
|
||||||
if not all([lead_id, current_action, next_action, next_action_date]):
|
if not all([lead_id, current_action, next_action]):
|
||||||
return JsonResponse({'success': False, 'message': 'All fields are required'}, status=400)
|
return JsonResponse({'success': False, 'message': 'All fields are required'}, status=400)
|
||||||
|
|
||||||
# Get the lead
|
# Get the lead
|
||||||
lead = models.Lead.objects.get(id=lead_id)
|
lead = models.Lead.objects.get(id=lead_id)
|
||||||
|
|
||||||
# Update lead fields
|
# Update lead fields
|
||||||
lead.action = current_action
|
lead.status = current_action
|
||||||
lead.next_action = next_action
|
lead.next_action = next_action
|
||||||
lead.next_action_date = next_action_date
|
|
||||||
|
|
||||||
# Parse the datetime string
|
# Parse the datetime string
|
||||||
try:
|
try:
|
||||||
|
if next_action_date:
|
||||||
|
lead.next_action_date = next_action_date
|
||||||
next_action_datetime = datetime.strptime(next_action_date, '%Y-%m-%dT%H:%M')
|
next_action_datetime = datetime.strptime(next_action_date, '%Y-%m-%dT%H:%M')
|
||||||
lead.next_action_date = timezone.make_aware(next_action_datetime)
|
lead.next_action_date = timezone.make_aware(next_action_datetime)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
@ -5060,10 +5066,6 @@ def send_lead_email(request, pk, email_pk=None):
|
|||||||
response["HX-Redirect"] = reverse("lead_detail", args=[lead.pk])
|
response["HX-Redirect"] = reverse("lead_detail", args=[lead.pk])
|
||||||
return response
|
return response
|
||||||
|
|
||||||
lead.status = models.Status.CONTACTED
|
|
||||||
lead.save()
|
|
||||||
|
|
||||||
|
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
email_pk = request.POST.get("email_pk")
|
email_pk = request.POST.get("email_pk")
|
||||||
if email_pk not in [None, "None", ""]:
|
if email_pk not in [None, "None", ""]:
|
||||||
@ -5138,11 +5140,16 @@ def add_activity_to_lead(request, pk):
|
|||||||
:return: An HTTP response that either renders the form or redirects to the lead detail page
|
:return: An HTTP response that either renders the form or redirects to the lead detail page
|
||||||
"""
|
"""
|
||||||
lead = get_object_or_404(models.Lead, pk=pk)
|
lead = get_object_or_404(models.Lead, pk=pk)
|
||||||
|
dealer = get_user_type(request)
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
form = forms.ActivityForm(request.POST)
|
form = forms.ActivityForm(request.POST)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
activity = form.save(commit=False)
|
activity = form.save(commit=False)
|
||||||
|
print(activity)
|
||||||
activity.content_object = lead
|
activity.content_object = lead
|
||||||
|
activity.dealer = dealer
|
||||||
|
activity.activity_type = form.cleaned_data["activity_type"]
|
||||||
|
activity.notes = form.cleaned_data["notes"]
|
||||||
activity.created_by = request.user
|
activity.created_by = request.user
|
||||||
activity.save()
|
activity.save()
|
||||||
return redirect("lead_detail", pk=pk)
|
return redirect("lead_detail", pk=pk)
|
||||||
@ -5151,7 +5158,7 @@ def add_activity_to_lead(request, pk):
|
|||||||
return render(request, "crm/add_activity.html", {"form": form, "lead": lead})
|
return render(request, "crm/add_activity.html", {"form": form, "lead": lead})
|
||||||
|
|
||||||
|
|
||||||
class OpportunityCreateView(CreateView, LoginRequiredMixin):
|
class OpportunityCreateView(CreateView,SuccessMessageMixin, LoginRequiredMixin):
|
||||||
"""
|
"""
|
||||||
Handles the creation of Opportunity instances through a form while enforcing
|
Handles the creation of Opportunity instances through a form while enforcing
|
||||||
specific user access control and initial data population. This view ensures
|
specific user access control and initial data population. This view ensures
|
||||||
@ -5173,30 +5180,33 @@ class OpportunityCreateView(CreateView, LoginRequiredMixin):
|
|||||||
model = models.Opportunity
|
model = models.Opportunity
|
||||||
form_class = forms.OpportunityForm
|
form_class = forms.OpportunityForm
|
||||||
template_name = "crm/opportunities/opportunity_form.html"
|
template_name = "crm/opportunities/opportunity_form.html"
|
||||||
|
success_message = "Opportunity created successfully."
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
dealer = get_user_type(self.request)
|
dealer = get_user_type(self.request)
|
||||||
return context
|
return context
|
||||||
|
|
||||||
def get_initial(self):
|
# def get_initial(self):
|
||||||
initial = super().get_initial()
|
# initial = super().get_initial()
|
||||||
if self.kwargs.get("pk", None):
|
# if self.kwargs.get("pk", None):
|
||||||
lead = models.Lead.objects.get(pk=self.kwargs.get("pk"))
|
# lead = models.Lead.objects.get(pk=self.kwargs.get("pk"))
|
||||||
|
|
||||||
initial["customer"] = lead.customer
|
# initial["customer"] = lead.customer
|
||||||
return initial
|
# return initial
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
dealer = get_user_type(self.request)
|
dealer = get_user_type(self.request)
|
||||||
form.instance.dealer = dealer
|
form.instance.dealer = dealer
|
||||||
|
form.instance.customer = form.instance.lead.customer
|
||||||
|
form.instance.staff = form.instance.lead.staff
|
||||||
return super().form_valid(form)
|
return super().form_valid(form)
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
return reverse_lazy("opportunity_detail", kwargs={"pk": self.object.pk})
|
return reverse_lazy("opportunity_detail", kwargs={"pk": self.object.pk})
|
||||||
|
|
||||||
|
|
||||||
class OpportunityUpdateView(LoginRequiredMixin, UpdateView):
|
class OpportunityUpdateView(LoginRequiredMixin,SuccessMessageMixin, UpdateView):
|
||||||
"""
|
"""
|
||||||
Handles the update functionality for Opportunity objects.
|
Handles the update functionality for Opportunity objects.
|
||||||
|
|
||||||
@ -5221,6 +5231,7 @@ class OpportunityUpdateView(LoginRequiredMixin, UpdateView):
|
|||||||
model = models.Opportunity
|
model = models.Opportunity
|
||||||
form_class = forms.OpportunityForm
|
form_class = forms.OpportunityForm
|
||||||
template_name = "crm/opportunities/opportunity_form.html"
|
template_name = "crm/opportunities/opportunity_form.html"
|
||||||
|
success_message = "Opportunity updated successfully."
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
return reverse_lazy("opportunity_detail", kwargs={"pk": self.object.pk})
|
return reverse_lazy("opportunity_detail", kwargs={"pk": self.object.pk})
|
||||||
@ -5252,7 +5263,6 @@ class OpportunityDetailView(LoginRequiredMixin, DetailView):
|
|||||||
url = reverse("opportunity_update_status", args=[self.object.pk])
|
url = reverse("opportunity_update_status", args=[self.object.pk])
|
||||||
form.fields["status"].widget.attrs["hx-get"] = url
|
form.fields["status"].widget.attrs["hx-get"] = url
|
||||||
form.fields["stage"].widget.attrs["hx-get"] = url
|
form.fields["stage"].widget.attrs["hx-get"] = url
|
||||||
form.fields["status"].initial = self.object.status
|
|
||||||
form.fields["stage"].initial = self.object.stage
|
form.fields["stage"].initial = self.object.stage
|
||||||
context["status_form"] = form
|
context["status_form"] = form
|
||||||
context["notes"] = models.Notes.objects.filter(
|
context["notes"] = models.Notes.objects.filter(
|
||||||
@ -5272,25 +5282,6 @@ class OpportunityDetailView(LoginRequiredMixin, DetailView):
|
|||||||
|
|
||||||
|
|
||||||
class OpportunityListView(LoginRequiredMixin, ListView):
|
class OpportunityListView(LoginRequiredMixin, ListView):
|
||||||
"""
|
|
||||||
View for displaying a paginated list of opportunities.
|
|
||||||
|
|
||||||
This class-based view inherits from `LoginRequiredMixin` and `ListView` to
|
|
||||||
provide a view rendering a list of `Opportunity` objects associated with
|
|
||||||
the current dealer. It ensures the user is authenticated before providing
|
|
||||||
access to the opportunity list and adds filtering based on the dealer
|
|
||||||
associated with the request.
|
|
||||||
|
|
||||||
:ivar model: The model used to retrieve opportunities.
|
|
||||||
:type model: models.Opportunity
|
|
||||||
:ivar template_name: The template used to render the opportunities list.
|
|
||||||
:type template_name: str
|
|
||||||
:ivar context_object_name: The context variable name for the list of
|
|
||||||
opportunities in the template.
|
|
||||||
:type context_object_name: str
|
|
||||||
:ivar paginate_by: The number of opportunities displayed per page.
|
|
||||||
:type paginate_by: int
|
|
||||||
"""
|
|
||||||
model = models.Opportunity
|
model = models.Opportunity
|
||||||
template_name = "crm/opportunities/opportunity_list.html"
|
template_name = "crm/opportunities/opportunity_list.html"
|
||||||
context_object_name = "opportunities"
|
context_object_name = "opportunities"
|
||||||
@ -5298,9 +5289,38 @@ class OpportunityListView(LoginRequiredMixin, ListView):
|
|||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
dealer = get_user_type(self.request)
|
dealer = get_user_type(self.request)
|
||||||
return models.Opportunity.objects.filter(dealer=dealer).all()
|
queryset = models.Opportunity.objects.filter(dealer=dealer)
|
||||||
|
|
||||||
|
# Search filter
|
||||||
|
search = self.request.GET.get('search')
|
||||||
|
if search:
|
||||||
|
queryset = queryset.filter(
|
||||||
|
Q(customer__customer_name__icontains=search) |
|
||||||
|
Q(customer__email__icontains=search))
|
||||||
|
|
||||||
|
# Stage filter
|
||||||
|
stage = self.request.GET.get('stage')
|
||||||
|
if stage:
|
||||||
|
queryset = queryset.filter(stage=stage)
|
||||||
|
|
||||||
|
# Sorting
|
||||||
|
sort = self.request.GET.get('sort', 'newest')
|
||||||
|
if sort == 'newest':
|
||||||
|
queryset = queryset.order_by('-created')
|
||||||
|
elif sort == 'highest':
|
||||||
|
queryset = queryset.order_by('-expected_revenue')
|
||||||
|
elif sort == 'closing':
|
||||||
|
queryset = queryset.order_by('closing_date')
|
||||||
|
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super().get_context_data(**kwargs)
|
||||||
|
context['stage_choices'] = models.Stage.choices
|
||||||
|
return context
|
||||||
|
|
||||||
|
def get_template_names(self):
|
||||||
|
return self.template_name
|
||||||
@login_required
|
@login_required
|
||||||
def delete_opportunity(request, pk):
|
def delete_opportunity(request, pk):
|
||||||
"""
|
"""
|
||||||
@ -7706,3 +7726,78 @@ def mark_all_notifications_as_read(request):
|
|||||||
def notifications_history(request):
|
def notifications_history(request):
|
||||||
models.Notification.objects.filter(user=request.user, is_read=False).update(read=True)
|
models.Notification.objects.filter(user=request.user, is_read=False).update(read=True)
|
||||||
return JsonResponse({'status': 'success'})
|
return JsonResponse({'status': 'success'})
|
||||||
|
|
||||||
|
# def activity_create(request,pk):
|
||||||
|
# lead = get_object_or_404(models.Lead, pk=pk)
|
||||||
|
# form = forms.ActivityHistoryForm()
|
||||||
|
# dealer = get_user_type(request)
|
||||||
|
# if request.method == "POST":
|
||||||
|
# form = forms.ActivityHistoryForm(request.POST)
|
||||||
|
# if form.is_valid():
|
||||||
|
# models.Activity.objects.create(
|
||||||
|
# dealer=dealer,
|
||||||
|
# activity_type=form.cleaned_data['activity_type'],
|
||||||
|
# notes=form.cleaned_data['description'],
|
||||||
|
# created_by=request.user,
|
||||||
|
# content_object=lead
|
||||||
|
# )
|
||||||
|
# return render(request, 'activity_history.html')
|
||||||
|
|
||||||
|
def add_activity(request,content_type,pk):
|
||||||
|
try:
|
||||||
|
model = apps.get_model(f'inventory.{content_type}')
|
||||||
|
except LookupError:
|
||||||
|
raise Http404("Model not found")
|
||||||
|
|
||||||
|
obj = get_object_or_404(model, pk=pk)
|
||||||
|
dealer = get_user_type(request)
|
||||||
|
if request.method == "POST":
|
||||||
|
form = forms.ActivityForm(request.POST)
|
||||||
|
if form.is_valid():
|
||||||
|
activity = form.save(commit=False)
|
||||||
|
activity.dealer = dealer
|
||||||
|
activity.content_object = obj
|
||||||
|
activity.created_by = request.user
|
||||||
|
activity.notes = form.cleaned_data['notes']
|
||||||
|
activity.activity_type = form.cleaned_data['activity_type']
|
||||||
|
|
||||||
|
activity.save()
|
||||||
|
messages.success(request, _("Activity added successfully"))
|
||||||
|
else:
|
||||||
|
messages.error(request, _("Activity form is not valid"))
|
||||||
|
return redirect(f"{content_type}_detail", pk=pk)
|
||||||
|
def add_task(request,content_type,pk):
|
||||||
|
try:
|
||||||
|
model = apps.get_model(f'inventory.{content_type}')
|
||||||
|
except LookupError:
|
||||||
|
raise Http404("Model not found")
|
||||||
|
|
||||||
|
obj = get_object_or_404(model, pk=pk)
|
||||||
|
dealer = get_user_type(request)
|
||||||
|
if request.method == "POST":
|
||||||
|
form = forms.StaffTaskForm(request.POST)
|
||||||
|
if form.is_valid():
|
||||||
|
task = form.save(commit=False)
|
||||||
|
task.dealer = dealer
|
||||||
|
task.content_object = obj
|
||||||
|
task.assigned_to = request.user
|
||||||
|
task.created_by = request.user
|
||||||
|
task.due_date = form.cleaned_data['due_date']
|
||||||
|
task.save()
|
||||||
|
messages.success(request, _("Task added successfully"))
|
||||||
|
else:
|
||||||
|
print(form.errors)
|
||||||
|
messages.error(request, _("Task form is not valid"))
|
||||||
|
return redirect(f"{content_type}_detail", pk=pk)
|
||||||
|
|
||||||
|
def update_task(request,pk):
|
||||||
|
task = get_object_or_404(models.Tasks, pk=pk)
|
||||||
|
if request.method == "POST":
|
||||||
|
task.completed = False if task.completed else True
|
||||||
|
task.save()
|
||||||
|
messages.success(request, _("Task updated successfully"))
|
||||||
|
else:
|
||||||
|
messages.error(request, _("Task form is not valid"))
|
||||||
|
response = HttpResponse()
|
||||||
|
response['HX-Refresh'] = 'true'
|
||||||
|
return response
|
||||||
@ -8,7 +8,7 @@
|
|||||||
{% endblock head_title %}
|
{% endblock head_title %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row ">
|
<div class="row ">
|
||||||
<div class="row flex-center min-vh-50">
|
<div class="row flex-center min-vh-50">
|
||||||
<div class="col-sm-10 col-md-8 col-lg-5 col-xl-5 col-xxl-3">
|
<div class="col-sm-10 col-md-8 col-lg-5 col-xl-5 col-xxl-3">
|
||||||
<a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'home' %}">
|
<a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'home' %}">
|
||||||
<div class="d-flex align-items-center fw-bolder fs-3 d-inline-block">
|
<div class="d-flex align-items-center fw-bolder fs-3 d-inline-block">
|
||||||
@ -44,6 +44,6 @@
|
|||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
{% endblock head_title %}
|
{% endblock head_title %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row ">
|
<div class="row ">
|
||||||
<div class="row flex-center min-vh-50">
|
<div class="row flex-center min-vh-50">
|
||||||
<div class="col-sm-10 col-md-8 col-lg-5 col-xl-5 col-xxl-3">
|
<div class="col-sm-10 col-md-8 col-lg-5 col-xl-5 col-xxl-3">
|
||||||
<a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'home' %}">
|
<a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'home' %}">
|
||||||
<div class="d-flex align-items-center fw-bolder fs-3 d-inline-block">
|
<div class="d-flex align-items-center fw-bolder fs-3 d-inline-block">
|
||||||
@ -30,9 +30,9 @@
|
|||||||
<div class="fs-9 fw-bold form-group mb-3 list-group">
|
<div class="fs-9 fw-bold form-group mb-3 list-group">
|
||||||
{% for radio in emailaddress_radios %}
|
{% for radio in emailaddress_radios %}
|
||||||
{% with emailaddress=radio.emailaddress %}
|
{% with emailaddress=radio.emailaddress %}
|
||||||
<label for="{{ radio.id }}">
|
<label for="{{ radio.id }}">
|
||||||
<input type="radio" name="email" checked="{{ radio.checked }}" value="{{ emailaddress.email }}" id="{{ radio.id }}" class="form-check-input mb-3" />
|
<input type="radio" name="email" checked="{{ radio.checked }}" value="{{ emailaddress.email }}" id="{{ radio.id }}" class="form-check-input mb-3" />
|
||||||
{{ emailaddress.email }}
|
{{ emailaddress.email }}
|
||||||
{% if emailaddress.verified %}
|
{% if emailaddress.verified %}
|
||||||
<span class="badge badge-phoenix badge-phoenix-success verified">{% translate "Verified" %}</span>
|
<span class="badge badge-phoenix badge-phoenix-success verified">{% translate "Verified" %}</span>
|
||||||
{% else %}
|
{% else %}
|
||||||
@ -42,9 +42,9 @@
|
|||||||
<span class="badge badge-phoenix badge-phoenix-primary email">{% translate "Primary" %}</span>
|
<span class="badge badge-phoenix badge-phoenix-primary email">{% translate "Primary" %}</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
</label>
|
</label>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-2 mb-6">
|
<div class="mt-2 mb-6">
|
||||||
<button type="submit" name="action_primary" class="btn btn-sm btn-primary">{% trans 'Make Primary' %}</button>
|
<button type="submit" name="action_primary" class="btn btn-sm btn-primary">{% trans 'Make Primary' %}</button>
|
||||||
<button type="submit" name="action_send" class="btn btn-sm btn-secondary">{% trans 'Re-send Verification' %}</button>
|
<button type="submit" name="action_send" class="btn btn-sm btn-secondary">{% trans 'Re-send Verification' %}</button>
|
||||||
@ -72,7 +72,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
(function() {
|
(function() {
|
||||||
var message = "{% trans 'Do you really want to remove the selected email address?' %}";
|
var message = "{% trans 'Do you really want to remove the selected email address?' %}";
|
||||||
var actions = document.getElementsByName('action_remove');
|
var actions = document.getElementsByName('action_remove');
|
||||||
if (actions.length) {
|
if (actions.length) {
|
||||||
@ -82,9 +82,9 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
{% endblock head_title %}
|
{% endblock head_title %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row ">
|
<div class="row ">
|
||||||
<div class="row flex-center min-vh-50">
|
<div class="row flex-center min-vh-50">
|
||||||
<div class="col-sm-10 col-md-8 col-lg-5 col-xl-5 col-xxl-3">
|
<div class="col-sm-10 col-md-8 col-lg-5 col-xl-5 col-xxl-3">
|
||||||
<a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'home' %}">
|
<a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'home' %}">
|
||||||
<div class="d-flex align-items-center fw-bolder fs-3 d-inline-block">
|
<div class="d-flex align-items-center fw-bolder fs-3 d-inline-block">
|
||||||
@ -48,6 +48,6 @@
|
|||||||
</p>
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
<section class="main my-2">
|
<section class="main my-2">
|
||||||
|
|
||||||
<div class="row flex-center ">
|
<div class="row flex-center ">
|
||||||
<div class="col-sm-10 col-md-8 col-lg-5 col-xl-5 col-xxl-3">
|
<div class="col-sm-10 col-md-8 col-lg-5 col-xl-5 col-xxl-3">
|
||||||
<a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'home' %}">
|
<a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'home' %}">
|
||||||
<div class="d-flex align-items-center fw-bolder fs-3 d-inline-block">
|
<div class="d-flex align-items-center fw-bolder fs-3 d-inline-block">
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
{% load i18n static %}
|
{% load i18n static %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="row flex-center min-vh-50 py-5">
|
<div class="row flex-center min-vh-50 py-5">
|
||||||
<div class="col-sm-10 col-md-8 col-lg-5 col-xxl-4">
|
<div class="col-sm-10 col-md-8 col-lg-5 col-xxl-4">
|
||||||
<a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'home' %}">
|
<a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'home' %}">
|
||||||
@ -34,5 +34,5 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -5,8 +5,8 @@
|
|||||||
{% trans "Change Password" %}
|
{% trans "Change Password" %}
|
||||||
{% endblock head_title %}
|
{% endblock head_title %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row ">
|
<div class="row ">
|
||||||
<div class="row flex-center min-vh-50">
|
<div class="row flex-center min-vh-50">
|
||||||
<div class="col-sm-10 col-md-8 col-lg-5 col-xl-5 col-xxl-3">
|
<div class="col-sm-10 col-md-8 col-lg-5 col-xl-5 col-xxl-3">
|
||||||
<a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'home' %}">
|
<a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'home' %}">
|
||||||
<div class="d-flex align-items-center fw-bolder fs-3 d-inline-block">
|
<div class="d-flex align-items-center fw-bolder fs-3 d-inline-block">
|
||||||
@ -29,6 +29,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
{% trans "Password Reset" %}
|
{% trans "Password Reset" %}
|
||||||
{% endblock head_title %}
|
{% endblock head_title %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row ">
|
<div class="row ">
|
||||||
<div class="row flex-center min-vh-50">
|
<div class="row flex-center min-vh-50">
|
||||||
<div class="col-sm-10 col-md-8 col-lg-5 col-xl-5 col-xxl-3">
|
<div class="col-sm-10 col-md-8 col-lg-5 col-xl-5 col-xxl-3">
|
||||||
<a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'home' %}">
|
<a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'home' %}">
|
||||||
@ -37,5 +37,5 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
{% endblock head_title %}
|
{% endblock head_title %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row ">
|
<div class="row ">
|
||||||
<div class="row flex-center min-vh-50">
|
<div class="row flex-center min-vh-50">
|
||||||
<div class="col-sm-10 col-md-8 col-lg-5 col-xl-5 col-xxl-3">
|
<div class="col-sm-10 col-md-8 col-lg-5 col-xl-5 col-xxl-3">
|
||||||
<a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'home' %}">
|
<a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'home' %}">
|
||||||
<div class="d-flex align-items-center fw-bolder fs-3 d-inline-block">
|
<div class="d-flex align-items-center fw-bolder fs-3 d-inline-block">
|
||||||
@ -28,6 +28,6 @@
|
|||||||
{% blocktrans %}We have sent you an email. If you have not received it please check your spam folder. Otherwise contact us if you do not receive it in a few minutes.{% endblocktrans %}
|
{% blocktrans %}We have sent you an email. If you have not received it please check your spam folder. Otherwise contact us if you do not receive it in a few minutes.{% endblocktrans %}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
{% endblock head_title %}
|
{% endblock head_title %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row ">
|
<div class="row ">
|
||||||
<div class="row flex-center min-vh-50">
|
<div class="row flex-center min-vh-50">
|
||||||
<div class="col-sm-10 col-md-8 col-lg-5 col-xl-5 col-xxl-3">
|
<div class="col-sm-10 col-md-8 col-lg-5 col-xl-5 col-xxl-3">
|
||||||
<a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'home' %}">
|
<a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'home' %}">
|
||||||
<div class="d-flex align-items-center fw-bolder fs-3 d-inline-block">
|
<div class="d-flex align-items-center fw-bolder fs-3 d-inline-block">
|
||||||
@ -37,10 +37,10 @@
|
|||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{{ redirect_field }}
|
{{ redirect_field }}
|
||||||
{{ form|crispy }}
|
{{ form|crispy }}
|
||||||
<button type="submit" class="btn btn-primary btn-sm w-100">{% trans 'Change Password' %}</button>
|
<button type="submit" class="btn btn-primary btn-sm w-100">{% trans 'Change Password' %}</button>
|
||||||
</form>
|
</form>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
{% endblock head_title %}
|
{% endblock head_title %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row ">
|
<div class="row ">
|
||||||
<div class="row flex-center min-vh-50">
|
<div class="row flex-center min-vh-50">
|
||||||
<div class="col-sm-10 col-md-8 col-lg-5 col-xl-5 col-xxl-3">
|
<div class="col-sm-10 col-md-8 col-lg-5 col-xl-5 col-xxl-3">
|
||||||
<a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'home' %}">
|
<a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'home' %}">
|
||||||
<div class="d-flex align-items-center fw-bolder fs-3 d-inline-block">
|
<div class="d-flex align-items-center fw-bolder fs-3 d-inline-block">
|
||||||
@ -23,6 +23,6 @@
|
|||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|||||||
@ -19,7 +19,7 @@
|
|||||||
<p class="text-body-tertiary fs-9">{% trans 'Create your account today' %}</p>
|
<p class="text-body-tertiary fs-9">{% trans 'Create your account today' %}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card theme-wizard" data-theme-wizard="data-theme-wizard">
|
<div class="card theme-wizard" data-theme-wizard="data-theme-wizard">
|
||||||
<div class="card-header pt-3 pb-2 ">
|
<div class="card-header pt-3 pb-2 ">
|
||||||
<ul class="nav justify-content-between nav-wizard nav-wizard-success" role="tablist">
|
<ul class="nav justify-content-between nav-wizard nav-wizard-success" role="tablist">
|
||||||
<li class="nav-item" role="presentation"><a class="nav-link active fw-semibold" href="#bootstrap-wizard-validation-tab1" data-bs-toggle="tab" data-wizard-step="1" aria-selected="true" role="tab">
|
<li class="nav-item" role="presentation"><a class="nav-link active fw-semibold" href="#bootstrap-wizard-validation-tab1" data-bs-toggle="tab" data-wizard-step="1" aria-selected="true" role="tab">
|
||||||
@ -77,7 +77,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@ -85,9 +85,9 @@
|
|||||||
{% include 'footer.html' %}
|
{% include 'footer.html' %}
|
||||||
</section>
|
</section>
|
||||||
<script src="{% static 'js/phoenix.js' %}"></script>
|
<script src="{% static 'js/phoenix.js' %}"></script>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|
||||||
{% block customJS %}
|
{% block customJS %}
|
||||||
<script src="https://unpkg.com/just-validate@latest/dist/just-validate.production.min.js"></script>
|
<script src="https://unpkg.com/just-validate@latest/dist/just-validate.production.min.js"></script>
|
||||||
<script>
|
<script>
|
||||||
const validator = new JustValidate('#wizardValidationForm1', {
|
const validator = new JustValidate('#wizardValidationForm1', {
|
||||||
@ -283,4 +283,4 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{% endblock customJS %}
|
{% endblock customJS %}
|
||||||
@ -5,7 +5,7 @@
|
|||||||
{% block title %}{{ _("Sign Up") }}{% endblock title %}
|
{% block title %}{{ _("Sign Up") }}{% endblock title %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="row min-vh-100 text-center">
|
<div class="row min-vh-100 text-center">
|
||||||
<div class="col-sm-10 col-md-8 col-lg-5 col-xl-5 col-xxl-3">
|
<div class="col-sm-10 col-md-8 col-lg-5 col-xl-5 col-xxl-3">
|
||||||
<a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'home' %}">
|
<a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'home' %}">
|
||||||
@ -34,7 +34,7 @@
|
|||||||
{% if SOCIALACCOUNT_ENABLED %}
|
{% if SOCIALACCOUNT_ENABLED %}
|
||||||
|
|
||||||
{% include "socialaccount/snippets/login.html" with page_layout="entrance" %}
|
{% include "socialaccount/snippets/login.html" with page_layout="entrance" %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<!-- Sign Up Form -->
|
<!-- Sign Up Form -->
|
||||||
{% if not SOCIALACCOUNT_ONLY %}
|
{% if not SOCIALACCOUNT_ONLY %}
|
||||||
|
|||||||
@ -21,13 +21,13 @@
|
|||||||
{% url 'account_email' as email_url %}
|
{% url 'account_email' as email_url %}
|
||||||
<p>
|
<p>
|
||||||
{% blocktrans %}This part of the site requires us to verify that
|
{% blocktrans %}This part of the site requires us to verify that
|
||||||
you are who you claim to be. For this purpose, we require that you
|
you are who you claim to be. For this purpose, we require that you
|
||||||
verify ownership of your email address. {% endblocktrans %}
|
verify ownership of your email address. {% endblocktrans %}
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
{% blocktrans %}We have sent an email to you for
|
{% blocktrans %}We have sent an email to you for
|
||||||
verification. Please click on the link inside that email. If you do not see the verification email in your main inbox, check your spam folder. Otherwise
|
verification. Please click on the link inside that email. If you do not see the verification email in your main inbox, check your spam folder. Otherwise
|
||||||
contact us if you do not receive it within a few minutes.{% endblocktrans %}
|
contact us if you do not receive it within a few minutes.{% endblocktrans %}
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
{% blocktrans %}<strong>Note:</strong> you can still <a href="{{ email_url }}">change your email address</a>.{% endblocktrans %}
|
{% blocktrans %}<strong>Note:</strong> you can still <a href="{{ email_url }}">change your email address</a>.{% endblocktrans %}
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
{% block description %}{{ page_description }}{% endblock %}
|
{% block description %}{{ page_description }}{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container py-5">
|
<div class="container py-5">
|
||||||
<div class="card bg-body">
|
<div class="card bg-body">
|
||||||
<div class="card-header ">
|
<div class="card-header ">
|
||||||
<h4 class="mb-0">{{ page_title }}</h4>
|
<h4 class="mb-0">{{ page_title }}</h4>
|
||||||
@ -88,7 +88,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block extra_js %}
|
{% block extra_js %}
|
||||||
|
|||||||
@ -111,7 +111,7 @@
|
|||||||
<button type="submit" class="btn btn-sm btn-phoenix-primary">{{ btn_text }}</button>
|
<button type="submit" class="btn btn-sm btn-phoenix-primary">{{ btn_text }}</button>
|
||||||
{% else %}
|
{% else %}
|
||||||
{% if request.user.is_superuser and service.id %}
|
{% if request.user.is_superuser and service.id %}
|
||||||
{% translate "Are you sure you want to delete this service?" as d_modal_message %}
|
{% translate "Are you sure you want to delete this service?" as d_modal_message %}
|
||||||
<div class="service-btn-container">
|
<div class="service-btn-container">
|
||||||
<a href="{% url 'appointment:update_service' service_id=service.id %}"
|
<a href="{% url 'appointment:update_service' service_id=service.id %}"
|
||||||
class="btn btn-sm btn-phoenix-primary">
|
class="btn btn-sm btn-phoenix-primary">
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
{% trans 'Service List' %}.
|
{% trans 'Service List' %}.
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block body %}
|
{% block body %}
|
||||||
{% translate "Confirm Deletion" as modal_title %}
|
{% translate "Confirm Deletion" as modal_title %}
|
||||||
{% translate "Delete" as delete_btn_modal %}
|
{% translate "Delete" as delete_btn_modal %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-6">
|
<div class="col-6">
|
||||||
@ -62,7 +62,7 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
{% include 'modal/confirm_modal.html' %}
|
{% include 'modal/confirm_modal.html' %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block title %}
|
{% block title %}
|
||||||
{{ _("Staff Members List")}}
|
{{ _("Staff Members List")}}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block description %}
|
{% block description %}
|
||||||
{% trans 'List of all staff members' %}.
|
{% trans 'List of all staff members' %}.
|
||||||
|
|||||||
@ -36,7 +36,7 @@
|
|||||||
<!-- ===============================================-->
|
<!-- ===============================================-->
|
||||||
|
|
||||||
|
|
||||||
<link href="{% static 'vendors/mapbox-gl/mapbox-gl.css' %}" rel="stylesheet">
|
<link href="{% static 'vendors/mapbox-gl/mapbox-gl.css' %}" rel="stylesheet">
|
||||||
<link href="{% static 'vendors/swiper/swiper-bundle.min.css' %}" rel="stylesheet">
|
<link href="{% static 'vendors/swiper/swiper-bundle.min.css' %}" rel="stylesheet">
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
|
||||||
@ -60,9 +60,9 @@
|
|||||||
|
|
||||||
<div class="content">
|
<div class="content">
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<!-- Main content goes here -->
|
<!-- Main content goes here -->
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@ -73,7 +73,7 @@
|
|||||||
<!-- ===============================================-->
|
<!-- ===============================================-->
|
||||||
<!-- End of Main Content-->
|
<!-- End of Main Content-->
|
||||||
<!-- ===============================================-->
|
<!-- ===============================================-->
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
data-bs-theme=""
|
data-bs-theme=""
|
||||||
data-navigation-type="default"
|
data-navigation-type="default"
|
||||||
data-navbar-horizontal-shape="default">
|
data-navbar-horizontal-shape="default">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block description %}
|
{% block description %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
</title>
|
</title>
|
||||||
<link rel="apple-touch-icon" sizes="180x180" href="{% static 'images/favicons/apple-touch-icon.png' %}">
|
<link rel="apple-touch-icon" sizes="180x180" href="{% static 'images/favicons/apple-touch-icon.png' %}">
|
||||||
<link rel="icon" type="image/png" sizes="32x32" href="{% static 'images/favicons/favicon-32x32.png' %}">
|
<link rel="icon" type="image/png" sizes="32x32" href="{% static 'images/favicons/favicon-32x32.png' %}">
|
||||||
@ -39,7 +39,7 @@
|
|||||||
|
|
||||||
<link href="{% static 'vendors/flatpickr/flatpickr.min.css' %}" rel="stylesheet">
|
<link href="{% static 'vendors/flatpickr/flatpickr.min.css' %}" rel="stylesheet">
|
||||||
<link href="{% static 'css/custom.css' %}" rel="stylesheet">
|
<link href="{% static 'css/custom.css' %}" rel="stylesheet">
|
||||||
<link rel="stylesheet" href="https://unicons.iconscout.com/release/v4.0.8/css/line.css">
|
<link rel="stylesheet" href="https://unicons.iconscout.com/release/v4.0.8/css/line.css">
|
||||||
{% if LANGUAGE_CODE == 'ar' %}
|
{% if LANGUAGE_CODE == 'ar' %}
|
||||||
<link href="{% static 'css/theme-rtl.min.css' %}" type="text/css" rel="stylesheet" id="style-rtl">
|
<link href="{% static 'css/theme-rtl.min.css' %}" type="text/css" rel="stylesheet" id="style-rtl">
|
||||||
<link href="{% static 'css/user-rtl.min.css' %}" type="text/css" rel="stylesheet" id="user-style-rtl">
|
<link href="{% static 'css/user-rtl.min.css' %}" type="text/css" rel="stylesheet" id="user-style-rtl">
|
||||||
@ -47,9 +47,9 @@
|
|||||||
<link href="{% static 'css/theme.min.css' %}" type="text/css" rel="stylesheet" id="style-default">
|
<link href="{% static 'css/theme.min.css' %}" type="text/css" rel="stylesheet" id="style-default">
|
||||||
<link href="{% static 'css/user.min.css' %}" type="text/css" rel="stylesheet" id="user-style-default">
|
<link href="{% static 'css/user.min.css' %}" type="text/css" rel="stylesheet" id="user-style-default">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<script src="{% static 'js/main.js' %}"></script>
|
<script src="{% static 'js/main.js' %}"></script>
|
||||||
<script src="{% static 'js/jquery.min.js' %}"></script>
|
<script src="{% static 'js/jquery.min.js' %}"></script>
|
||||||
<script src="{% static 'js/echarts.js' %}"></script>
|
<script src="{% static 'js/echarts.js' %}"></script>
|
||||||
|
|
||||||
<!--<style>
|
<!--<style>
|
||||||
.btn{
|
.btn{
|
||||||
@ -59,18 +59,18 @@
|
|||||||
padding-bottom: 4px;
|
padding-bottom: 4px;
|
||||||
}
|
}
|
||||||
</style>-->
|
</style>-->
|
||||||
{% block customCSS %}
|
{% block customCSS %}
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
</head>
|
</head>
|
||||||
<body hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'>
|
<body hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'>
|
||||||
|
|
||||||
{% include "toast-alert.html" %}
|
{% include "toast-alert.html" %}
|
||||||
<main class="main" id="top">
|
<main class="main" id="top">
|
||||||
{% include 'header.html' %}
|
{% include 'header.html' %}
|
||||||
|
|
||||||
<div class="content">
|
<div class="content">
|
||||||
{% include "plans/expiration_messages.html" %}
|
{% include "plans/expiration_messages.html" %}
|
||||||
{% block period_navigation %}
|
{% block period_navigation %}
|
||||||
|
|
||||||
{% endblock period_navigation %}
|
{% endblock period_navigation %}
|
||||||
@ -80,9 +80,9 @@
|
|||||||
{% block body %}
|
{% block body %}
|
||||||
{% endblock body%}
|
{% endblock body%}
|
||||||
|
|
||||||
<div class="my-3"></div>
|
<div class="my-3"></div>
|
||||||
{% include 'footer.html' %}
|
{% include 'footer.html' %}
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
<script src="{% static 'js/djetler.bundle.js' %}"></script>
|
<script src="{% static 'js/djetler.bundle.js' %}"></script>
|
||||||
<script src="{% static 'js/js-utils.js' %}"></script>
|
<script src="{% static 'js/js-utils.js' %}"></script>
|
||||||
@ -114,7 +114,7 @@
|
|||||||
<script src="{% static 'vendors/swiper/swiper-bundle.min.js' %}"></script>
|
<script src="{% static 'vendors/swiper/swiper-bundle.min.js' %}"></script>
|
||||||
<script src="{% static 'vendors/flatpickr/flatpickr.min.js' %}"></script>
|
<script src="{% static 'vendors/flatpickr/flatpickr.min.js' %}"></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
{% if entity_slug %}
|
{% if entity_slug %}
|
||||||
let entitySlug = "{{ view.kwargs.entity_slug }}"
|
let entitySlug = "{{ view.kwargs.entity_slug }}"
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@ -40,4 +40,4 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-support-chat p-0 border border-translucent"><span class="fs-8 btn-text text-primary text-nowrap">Chat demo</span><span class="ping-icon-wrapper mt-n4 ms-n6 mt-sm-0 ms-sm-2 position-absolute position-sm-relative"><span class="ping-icon-bg"></span><span class="fa-solid fa-circle ping-icon"></span></span><span class="fa-solid fa-headset text-primary fs-8 d-sm-none"></span><span class="fa-solid fa-chevron-down text-primary fs-7"></span></button>
|
<button class="btn btn-support-chat p-0 border border-translucent"><span class="fs-8 btn-text text-primary text-nowrap">Chat demo</span><span class="ping-icon-wrapper mt-n4 ms-n6 mt-sm-0 ms-sm-2 position-absolute position-sm-relative"><span class="ping-icon-bg"></span><span class="fa-solid fa-circle ping-icon"></span></span><span class="fa-solid fa-headset text-primary fs-8 d-sm-none"></span><span class="fa-solid fa-chevron-down text-primary fs-7"></span></button>
|
||||||
</div>
|
</div>
|
||||||
30
templates/components/activity_modal.html
Normal file
30
templates/components/activity_modal.html
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
{% load static i18n crispy_forms_tags %}
|
||||||
|
<!-- activity Modal -->
|
||||||
|
<div class="modal fade" id="activityModal" tabindex="-1" aria-labelledby="activityModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog modal-md">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header justify-content-between align-items-start gap-5 px-4 pt-4 pb-3 border-0">
|
||||||
|
<h4 class="modal-title" id="noteModalLabel">{% trans 'Activity' %}</h4>
|
||||||
|
<button class="btn p-0 text-body-quaternary fs-6" data-bs-dismiss="modal" aria-label="Close">
|
||||||
|
<span class="fas fa-times"></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<form action="{% url 'add_activity' content_type=content_type pk=pk %}" method="post" class="add_activity_form">
|
||||||
|
{% csrf_token %}
|
||||||
|
<div class="mb-2 form-group">
|
||||||
|
<select class="form-select" name="activity_type" id="activity_type">
|
||||||
|
<option value="call">{% trans 'Call' %}</option>
|
||||||
|
<option value="email">{% trans 'Email' %}</option>
|
||||||
|
<option value="meeting">{% trans 'Meeting' %}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3 form-group">
|
||||||
|
<textarea class="form-control" name="notes" id="notes" rows="6"></textarea>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-success w-100">{% trans 'Save' %}</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@ -2,10 +2,10 @@
|
|||||||
{% load i18n static crispy_forms_filters %}
|
{% load i18n static crispy_forms_filters %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>Add Activity to {{ lead.first_name }} {{ lead.last_name }}</h1>
|
<h1>Add Activity to {{ lead.first_name }} {{ lead.last_name }}</h1>
|
||||||
<form method="post">
|
<form method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{{ form|crispy }}
|
{{ form|crispy }}
|
||||||
<button class="btn btn-phoenix-primary" type="submit">Add Activity</button>
|
<button class="btn btn-phoenix-primary" type="submit">Add Activity</button>
|
||||||
</form>
|
</form>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -1,9 +1,9 @@
|
|||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
{% load static %}
|
{% load static %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="table-responsive border-translucent">
|
<div class="table-responsive border-translucent">
|
||||||
<table class="table table-sm fs-9">
|
<table class="table table-sm fs-9">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Customer</th>
|
<th>Customer</th>
|
||||||
@ -32,7 +32,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -1,10 +1,10 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Title</title>
|
<title>Title</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@ -1,18 +1,97 @@
|
|||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
{% load i18n static %}
|
{% load i18n static humanize %}
|
||||||
{% block content %}
|
|
||||||
{% load crispy_forms_tags %}
|
{% load crispy_forms_tags %}
|
||||||
|
|
||||||
{% block customCSS %}
|
{% block customCSS %}
|
||||||
<style>
|
<style>
|
||||||
.main-tab li:last-child {
|
.main-tab li:last-child {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
}
|
}
|
||||||
</style>
|
.completed-task {
|
||||||
{% endblock customCSS %}
|
text-decoration: line-through;
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
.kanban-header {
|
||||||
|
position: relative;
|
||||||
|
background-color:rgb(237, 241, 245);
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
color: #333;
|
||||||
|
clip-path: polygon(0 0, calc(100% - 15px) 0, 100% 50%, calc(100% - 15px) 100%, 0 100%);
|
||||||
|
box-shadow: 0 1px 2px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.kanban-header::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
right: -20px;
|
||||||
|
top: 0;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
border-top: 28px solid transparent;
|
||||||
|
border-bottom: 28px solid transparent;
|
||||||
|
border-left: 20px solid #dee2e6;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
{% endblock customCSS %}
|
||||||
|
{% block content %}
|
||||||
|
<div class="row g-3">
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="modal fade" id="actionTrackingModal" tabindex="-1" aria-labelledby="actionTrackingModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" id="actionTrackingModalLabel">{{ _("Update Lead Actions") }}</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<form id="actionTrackingForm" method="post">
|
||||||
|
<div class="modal-body">
|
||||||
|
{% csrf_token %}
|
||||||
|
<input type="hidden" id="leadId" name="lead_id">
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="currentAction" class="form-label">{{ _("Current Action") }}</label>
|
||||||
|
<select class="form-select" id="currentAction" name="current_action" required>
|
||||||
|
<option value="">{{ _("Select Action") }}</option>
|
||||||
|
<option value="follow_up">{{ _("Follow Up") }}</option>
|
||||||
|
<option value="negotiation">{{ _("Negotiation") }}</option>
|
||||||
|
<option value="won">{{ _("Won") }}</option>
|
||||||
|
<option value="lost">{{ _("Lost") }}</option>
|
||||||
|
<option value="closed">{{ _("Closed") }}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="nextAction" class="form-label">{{ _("Next Action") }}</label>
|
||||||
|
<select class="form-select" id="nextAction" name="next_action" required>
|
||||||
|
<option value="">{{ _("Select Next Action") }}</option>
|
||||||
|
<option value="no_action">{{ _("No Action") }}</option>
|
||||||
|
<option value="call">{{ _("Call") }}</option>
|
||||||
|
<option value="meeting">{{ _("Meeting") }}</option>
|
||||||
|
<option value="email">{{ _("Email") }}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="nextActionDate" class="form-label">{{ _("Next Action Date") }}</label>
|
||||||
|
<input type="datetime-local" class="form-control" id="nextActionDate" name="next_action_date">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="actionNotes" class="form-label">{{ _("Notes") }}</label>
|
||||||
|
<textarea class="form-control" id="actionNotes" name="action_notes" rows="3"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{{ _("Close") }}</button>
|
||||||
|
<button type="submit" class="btn btn-primary">{{ _("Save Changes") }}</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="row g-3">
|
|
||||||
<div class="col-12">
|
|
||||||
<div class="row align-items-center justify-content-between g-3 mb-3">
|
<div class="row align-items-center justify-content-between g-3 mb-3">
|
||||||
<div class="col-12 col-md-auto">
|
<div class="col-12 col-md-auto">
|
||||||
<h4 class="mb-0">{{ _("Lead Details")}}</h4>
|
<h4 class="mb-0">{{ _("Lead Details")}}</h4>
|
||||||
@ -25,10 +104,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row g-0 g-md-4 g-xl-6">
|
<div class="row g-0 g-md-4 g-xl-6">
|
||||||
<div class="col-md-5 col-lg-5 col-xl-4">
|
<div class="col-md-5 col-lg-5 col-xl-4">
|
||||||
<div class="sticky-leads-sidebar">
|
<div class="sticky-leads-sidebar">
|
||||||
<div class="lead-details" data-breakpoint="md">
|
<div class="lead-details" data-breakpoint="md">
|
||||||
<div class="d-flex justify-content-between align-items-center mb-2 d-md-none">
|
<div class="d-flex justify-content-between align-items-center mb-2 d-md-none">
|
||||||
@ -99,7 +178,7 @@
|
|||||||
<div class="d-flex align-items-center mb-1"><span class="me-2 uil uil-clock"></span>
|
<div class="d-flex align-items-center mb-1"><span class="me-2 uil uil-clock"></span>
|
||||||
<h5 class="text-body-highlight mb-0">{{ _("Created")}}</h5>
|
<h5 class="text-body-highlight mb-0">{{ _("Created")}}</h5>
|
||||||
</div>
|
</div>
|
||||||
<p class="mb-0 text-body-secondary">{{ lead.created|date }}</p>
|
<p class="mb-0 text-body-secondary">{{ lead.created|naturalday|capfirst }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<div class="d-flex align-items-center mb-1"><span class="me-2 uil uil-file-check-alt"></span>
|
<div class="d-flex align-items-center mb-1"><span class="me-2 uil uil-file-check-alt"></span>
|
||||||
@ -130,14 +209,24 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="d-lg-none top-0"></div>
|
<div class="d-lg-none top-0"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-7 col-lg-7 col-xl-8">
|
<div class="col-md-7 col-lg-7 col-xl-8">
|
||||||
<ul class="nav main-tab nav-underline fs-9 deal-details scrollbar flex-nowrap w-100 pb-1 mb-6 justify-content-end" id="myTab" role="tablist" style="overflow-y: hidden;">
|
<div class="d-flex w-100 gap-5">
|
||||||
|
<div class="kanban-header bg-success w-50 text-white fw-bold"><i class="fa-solid fa-circle-check me-2"></i>{{lead.status|capfirst}} <br> <small>{% trans "Current Stage" %}</small></div>
|
||||||
|
<div class="kanban-header bg-secondary w-50 text-white fw-bold"><i class="fa-solid fa-circle-info me-2"></i>{{lead.next_action|capfirst}} <br> <small>{% trans "Next Action" %}</small></div>
|
||||||
|
</div>
|
||||||
|
<ul class="nav main-tab nav-underline fs-9 deal-details scrollbar flex-nowrap w-100 pb-1 mb-6 justify-content-end mt-5" id="myTab" role="tablist" style="overflow-y: hidden;">
|
||||||
<li class="nav-item text-nowrap me-2" role="presentation"><a class="nav-link active" id="activity-tab" data-bs-toggle="tab" href="#tab-activity" role="tab" aria-controls="tab-activity" aria-selected="false" tabindex="-1"> <span class="fa-solid fa-chart-line me-2 tab-icon-color fs-8"></span>{{ _("Activity") }}</a></li>
|
<li class="nav-item text-nowrap me-2" role="presentation"><a class="nav-link active" id="activity-tab" data-bs-toggle="tab" href="#tab-activity" role="tab" aria-controls="tab-activity" aria-selected="false" tabindex="-1"> <span class="fa-solid fa-chart-line me-2 tab-icon-color fs-8"></span>{{ _("Activity") }}</a></li>
|
||||||
<li class="nav-item text-nowrap me-2" role="presentation"><a class="nav-link" id="notes-tab" data-bs-toggle="tab" href="#tab-notes" role="tab" aria-controls="tab-notes" aria-selected="false" tabindex="-1"> <span class="fa-solid fa-clipboard me-2 tab-icon-color fs-8"></span>{{ _("Notes") }}</a></li>
|
<li class="nav-item text-nowrap me-2" role="presentation"><a class="nav-link" id="notes-tab" data-bs-toggle="tab" href="#tab-notes" role="tab" aria-controls="tab-notes" aria-selected="false" tabindex="-1"> <span class="fa-solid fa-clipboard me-2 tab-icon-color fs-8"></span>{{ _("Notes") }}</a></li>
|
||||||
<li class="nav-item text-nowrap me-2" role="presentation"><a class="nav-link" id="emails-tab" data-bs-toggle="tab" href="#tab-emails" role="tab" aria-controls="tab-emails" aria-selected="true"> <span class="fa-solid fa-envelope me-2 tab-icon-color fs-8"></span>{{ _("Emails") }}</a></li>
|
<li class="nav-item text-nowrap me-2" role="presentation"><a class="nav-link" id="emails-tab" data-bs-toggle="tab" href="#tab-emails" role="tab" aria-controls="tab-emails" aria-selected="true"> <span class="fa-solid fa-envelope me-2 tab-icon-color fs-8"></span>{{ _("Emails") }}</a></li>
|
||||||
|
<li class="nav-item text-nowrap me-2" role="presentation"><a class="nav-link" id="tasks-tab" data-bs-toggle="tab" href="#tab-tasks" role="tab" aria-controls="tab-tasks" aria-selected="true"> <span class="fa-solid fa-envelope me-2 tab-icon-color fs-8"></span>{{ _("Tasks") }}</a></li>
|
||||||
<li class="nav-item text-nowrap ml-auto" role="presentation">
|
<li class="nav-item text-nowrap ml-auto" role="presentation">
|
||||||
<button class="btn btn-primary" type="button" data-bs-toggle="modal" data-bs-target="#exampleModal">Reassign Lead</button>
|
<button class="btn btn-info btn-sm" type="button" data-bs-toggle="modal" data-bs-target="#exampleModal"> <i class="fa-solid fa-user-plus me-2"></i> Create Opportunity</button>
|
||||||
|
<button class="btn btn-primary btn-sm" type="button" data-bs-toggle="modal" data-bs-target="#exampleModal"> <i class="fa-solid fa-user-plus me-2"></i> Reassign Lead</button>
|
||||||
|
<button class="btn btn-primary btn-sm" onclick="openActionModal('{{ lead.id }}', '{{ lead.action }}', '{{ lead.next_action }}', '{{ lead.next_action_date|date:"Y-m-d\TH:i" }}')">
|
||||||
|
<i class="fa-solid fa-user-plus me-2"></i>
|
||||||
|
{% trans "Update Actions" %}
|
||||||
|
</button>
|
||||||
<div class="modal fade" id="exampleModal" tabindex="-1" aria-hidden="true">
|
<div class="modal fade" id="exampleModal" tabindex="-1" aria-hidden="true">
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
@ -162,8 +251,9 @@
|
|||||||
</ul>
|
</ul>
|
||||||
<div class="tab-content" id="myTabContent">
|
<div class="tab-content" id="myTabContent">
|
||||||
<div class="tab-pane fade active show" id="tab-activity" role="tabpanel" aria-labelledby="activity-tab">
|
<div class="tab-pane fade active show" id="tab-activity" role="tabpanel" aria-labelledby="activity-tab">
|
||||||
<div class="mb-1">
|
<div class="mb-1 d-flex justify-content-between align-items-center">
|
||||||
<h3 class="mb-4" id="scrollspyTask">{{ _("Activities") }} <span class="fw-light fs-7">({{ activities.count}})</span></h3>
|
<h3 class="mb-4" id="scrollspyTask">{{ _("Activities") }} <span class="fw-light fs-7">({{ activities.count}})</span></h3>
|
||||||
|
<button class="btn btn-phoenix-primary btn-sm" type="button" data-bs-toggle="modal" data-bs-target="#activityModal"><span class="fas fa-plus me-1"></span>{{ _("Add Activity") }}</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="row justify-content-between align-items-md-center hover-actions-trigger btn-reveal-trigger border-translucent py-3 gx-0 border-top">
|
<div class="row justify-content-between align-items-md-center hover-actions-trigger btn-reveal-trigger border-translucent py-3 gx-0 border-top">
|
||||||
<div class="col-12 col-lg-auto">
|
<div class="col-12 col-lg-auto">
|
||||||
@ -196,9 +286,9 @@
|
|||||||
<div class="d-flex mb-2">
|
<div class="d-flex mb-2">
|
||||||
<h6 class="lh-sm mb-0 me-2 text-body-secondary timeline-item-title">{{ activity.activity_type|capfirst }}</h6>
|
<h6 class="lh-sm mb-0 me-2 text-body-secondary timeline-item-title">{{ activity.activity_type|capfirst }}</h6>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-body-quaternary fs-9 mb-0 text-nowrap timeline-time"><span class="fa-regular fa-clock me-1"></span>{{ activity.created }}</p>
|
<p class="text-body-quaternary fs-9 mb-0 text-nowrap timeline-time"><span class="fa-regular fa-clock me-1"></span>{{ activity.created|naturalday|capfirst }}</p>
|
||||||
</div>
|
</div>
|
||||||
<h6 class="fs-10 fw-normal mb-3">{{ _("by") }} <a class="fw-semibold" href="#!">{{ activity.created_by }}</a></h6>
|
<h6 class="fs-10 fw-normal mb-3">{{ _("created by") }} <a class="fw-semibold" href="#!">{{ activity.created_by }}</a></h6>
|
||||||
<p class="fs-9 text-body-secondary w-sm-60 mb-5">{{ activity.notes }}</p>
|
<p class="fs-9 text-body-secondary w-sm-60 mb-5">{{ activity.notes }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -209,15 +299,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-pane fade" id="tab-notes" role="tabpanel" aria-labelledby="notes-tab">
|
<div class="tab-pane fade" id="tab-notes" role="tabpanel" aria-labelledby="notes-tab">
|
||||||
<div class="mb-1">
|
<div class="mb-1 d-flex align-items-center justify-content-between">
|
||||||
<h3 class="mb-4" id="scrollspyNotes">{{ _("Notes") }}</h3>
|
<h3 class="mb-4" id="scrollspyNotes">{{ _("Notes") }}</h3>
|
||||||
</div>
|
<a id="addBtn" href="#" class="btn btn-sm btn-phoenix-primary mb-3 btn-sm" data-url="{% url 'add_note_to_lead' lead.pk %}" data-bs-toggle="modal" data-bs-target="#noteModal" data-note-title="{{ _("Add") }}<i class='fa fa-plus-circle text-success ms-2'></i>">
|
||||||
<div class="d-flex align-items-center justify-content-start">
|
|
||||||
<a id="addBtn" href="#" class="btn btn-sm btn-phoenix-primary mb-3" data-url="{% url 'add_note_to_lead' lead.pk %}" data-bs-toggle="modal" data-bs-target="#noteModal" data-note-title="{{ _("Add") }}<i class='fa fa-plus-circle text-success ms-2'></i>">
|
|
||||||
<span class="fas fa-plus me-1"></span>
|
<span class="fas fa-plus me-1"></span>
|
||||||
{% trans 'Add Note' %}
|
{% trans 'Add Note' %}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="border-top border-bottom border-translucent" id="leadDetailsTable">
|
<div class="border-top border-bottom border-translucent" id="leadDetailsTable">
|
||||||
<div class="table-responsive scrollbar mx-n1 px-1">
|
<div class="table-responsive scrollbar mx-n1 px-1">
|
||||||
<table class="table fs-9 mb-0">
|
<table class="table fs-9 mb-0">
|
||||||
@ -239,7 +328,7 @@
|
|||||||
{% else %}
|
{% else %}
|
||||||
<td class="align-middle white-space-nowrap text-start white-space-nowrap">{{ note.created_by.dealer.get_local_name|default:note.created_by.dealer.name }}</td>
|
<td class="align-middle white-space-nowrap text-start white-space-nowrap">{{ note.created_by.dealer.get_local_name|default:note.created_by.dealer.name }}</td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<td class="align-middle text-body-tertiary text-start white-space-nowrap">{{ note.created }}</td>
|
<td class="align-middle text-body-tertiary text-start white-space-nowrap">{{ note.created|naturalday|capfirst }}</td>
|
||||||
<td class="align-middle text-end white-space-nowrap pe-0 action py-2">
|
<td class="align-middle text-end white-space-nowrap pe-0 action py-2">
|
||||||
{% if note.created_by == request.user %}
|
{% if note.created_by == request.user %}
|
||||||
<a id="updateBtn" href="#" class="btn btn-sm btn-phoenix-primary me-2" data-url="{% url 'update_note_to_lead' note.pk %}" data-bs-toggle="modal" data-bs-target="#noteModal" data-note-title="{{ _("Update") }}<i class='fas fa-pen-square text-primary ms-2'></i>">
|
<a id="updateBtn" href="#" class="btn btn-sm btn-phoenix-primary me-2" data-url="{% url 'update_note_to_lead' note.pk %}" data-bs-toggle="modal" data-bs-target="#noteModal" data-note-title="{{ _("Update") }}<i class='fas fa-pen-square text-primary ms-2'></i>">
|
||||||
@ -261,8 +350,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-pane fade" id="tab-emails" role="tabpanel" aria-labelledby="emails-tab">
|
<div class="tab-pane fade" id="tab-emails" role="tabpanel" aria-labelledby="emails-tab">
|
||||||
<div class="mb-1">
|
<div class="mb-1 d-flex justify-content-between align-items-center">
|
||||||
<h3 class="mb-0" id="scrollspyEmails">{{ _("Emails") }}</h3>
|
<h3 class="mb-0" id="scrollspyEmails">{{ _("Emails") }}</h3>
|
||||||
|
<a href="{% url 'send_lead_email' lead.pk %}">
|
||||||
|
<button type="button" class="btn btn-sm btn-phoenix-primary">
|
||||||
|
<span class="fas fa-plus me-1"></span>
|
||||||
|
{% trans 'Send Email' %}
|
||||||
|
</button>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div class="scrollbar">
|
<div class="scrollbar">
|
||||||
@ -302,7 +397,7 @@
|
|||||||
<div class="fs-10 d-block">{{email.to_email}}</div>
|
<div class="fs-10 d-block">{{email.to_email}}</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="sent align-middle white-space-nowrap text-start fw-bold text-body-tertiary py-2">{{email.from_email}}</td>
|
<td class="sent align-middle white-space-nowrap text-start fw-bold text-body-tertiary py-2">{{email.from_email}}</td>
|
||||||
<td class="date align-middle white-space-nowrap text-body py-2">{{email.created}}</td>
|
<td class="date align-middle white-space-nowrap text-body py-2">{{email.created|naturalday}}</td>
|
||||||
<td class="align-middle white-space-nowrap ps-3"><a class="text-body" href=""><span class="fa-solid fa-phone text-primary me-2"></span>Call</a></td>
|
<td class="align-middle white-space-nowrap ps-3"><a class="text-body" href=""><span class="fa-solid fa-phone text-primary me-2"></span>Call</a></td>
|
||||||
<td class="status align-middle fw-semibold text-end py-2"><span class="badge badge-phoenix fs-10 badge-phoenix-success">sent</span></td>
|
<td class="status align-middle fw-semibold text-end py-2"><span class="badge badge-phoenix fs-10 badge-phoenix-success">sent</span></td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -375,13 +470,73 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% comment %} {% endcomment %}
|
||||||
|
<div class="tab-pane fade" id="tab-tasks" role="tabpanel" aria-labelledby="tasks-tab">
|
||||||
|
<div class="mb-1 d-flex justify-content-between align-items-center">
|
||||||
|
<h3 class="mb-0" id="scrollspyEmails">{{ _("Tasks") }}</h3>
|
||||||
|
<button class="btn btn-phoenix-primary btn-sm" type="button" data-bs-toggle="modal" data-bs-target="#taskModal"><span class="fas fa-plus me-1"></span>{{ _("Add Task") }}</button>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<div class="border-top border-bottom border-translucent" id="allEmailsTable" data-list='{"valueNames":["subject","sent","date","source","status"],"page":7,"pagination":true}'>
|
||||||
|
<div class="table-responsive scrollbar mx-n1 px-1">
|
||||||
|
<table class="table fs-9 mb-0">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="white-space-nowrap fs-9 align-middle ps-0" style="width:26px;">
|
||||||
|
<div class="form-check mb-0 fs-8">
|
||||||
|
<input class="form-check-input" type="checkbox" data-bulk-select='{"body":"all-email-table-body"}' />
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
<th class="sort white-space-nowrap align-middle pe-3 ps-0 text-uppercase" scope="col" data-sort="subject" style="width:31%; min-width:350px">Title</th>
|
||||||
|
<th class="sort align-middle pe-3 text-uppercase" scope="col" data-sort="sent" style="width:15%; min-width:130px">Assigned to</th>
|
||||||
|
<th class="sort align-middle text-start text-uppercase" scope="col" data-sort="date" style="min-width:165px">Due Date</th>
|
||||||
|
<th class="sort align-middle text-start text-uppercase" scope="col" data-sort="date" style="min-width:165px">Completed</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody class="list" id="all-email-table-body">
|
||||||
|
{% for task in tasks %}
|
||||||
|
<tr class="hover-actions-trigger btn-reveal-trigger position-static {% if task.completed %}completed-task{% endif %}">
|
||||||
|
<td class="fs-9 align-middle px-0 py-3">
|
||||||
|
<div class="form-check mb-0 fs-8">
|
||||||
|
<input class="form-check-input" type="checkbox" hx-post="{% url 'update_task' task.pk %}" hx-trigger="change" hx-swap="none" />
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td class="subject order align-middle white-space-nowrap py-2 ps-0"><a class="fw-semibold text-primary" href="">{{task.title}}</a>
|
||||||
|
<div class="fs-10 d-block">{{task.description}}</div>
|
||||||
|
</td>
|
||||||
|
<td class="sent align-middle white-space-nowrap text-start fw-bold text-body-tertiary py-2">{{task.assigned_to}}</td>
|
||||||
|
<td class="date align-middle white-space-nowrap text-body py-2">{{task.created|naturalday|capfirst}}</td>
|
||||||
|
<td class="date align-middle white-space-nowrap text-body py-2">
|
||||||
|
{% if task.completed %}
|
||||||
|
<span class="badge badge-phoenix fs-10 badge-phoenix-success"><i class="fa-solid fa-check"></i></span>
|
||||||
|
{% else %}
|
||||||
|
<span class="badge badge-phoenix fs-10 badge-phoenix-warning"><i class="fa-solid fa-xmark"></i></span>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="row align-items-center justify-content-between py-2 pe-0 fs-9">
|
||||||
|
<div class="col-auto d-flex">
|
||||||
|
<p class="mb-0 d-none d-sm-block me-3 fw-semibold text-body" data-list-info="data-list-info"></p><a class="fw-semibold" href="" data-list-view="*">View all<span class="fas fa-angle-right ms-1" data-fa-transform="down-1"></span></a><a class="fw-semibold d-none" href="" data-list-view="less">View Less<span class="fas fa-angle-right ms-1" data-fa-transform="down-1"></span></a>
|
||||||
|
</div>
|
||||||
|
<div class="col-auto d-flex">
|
||||||
|
<button class="page-link" data-list-pagination="prev"><span class="fas fa-chevron-left"></span></button>
|
||||||
|
<ul class="mb-0 pagination"></ul>
|
||||||
|
<button class="page-link pe-0" data-list-pagination="next"><span class="fas fa-chevron-right"></span></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% include 'modal/delete_modal.html' %}
|
{% include 'modal/delete_modal.html' %}
|
||||||
<!-- add update Modal -->
|
<!-- add update Modal -->
|
||||||
<div class="modal fade" id="noteModal" tabindex="-1" aria-labelledby="noteModalLabel" aria-hidden="true">
|
<div class="modal fade" id="noteModal" tabindex="-1" aria-labelledby="noteModalLabel" aria-hidden="true">
|
||||||
<div class="modal-dialog modal-sm">
|
<div class="modal-dialog modal-md">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header justify-content-between align-items-start gap-5 px-4 pt-4 pb-3 border-0">
|
<div class="modal-header justify-content-between align-items-start gap-5 px-4 pt-4 pb-3 border-0">
|
||||||
<h4 class="modal-title" id="noteModalLabel">{% trans 'Notes' %}</h4>
|
<h4 class="modal-title" id="noteModalLabel">{% trans 'Notes' %}</h4>
|
||||||
@ -394,9 +549,36 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
<!-- activity Modal -->
|
||||||
|
{% include "components/activity_modal.html" with content_type="lead" pk=lead.pk %}
|
||||||
|
<!-- task Modal -->
|
||||||
|
<div class="modal fade" id="taskModal" tabindex="-1" aria-labelledby="taskModalLabel" aria-hidden="true">
|
||||||
|
|
||||||
|
<div class="modal-dialog modal-md">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header justify-content-between align-items-start gap-5 px-4 pt-4 pb-3 border-0">
|
||||||
|
<h4 class="modal-title" id="noteModalLabel">{% trans 'Task' %}</h4>
|
||||||
|
<button class="btn p-0 text-body-quaternary fs-6" data-bs-dismiss="modal" aria-label="Close">
|
||||||
|
<span class="fas fa-times"></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<form action="{% url 'add_task' 'lead' lead.pk %}" method="post" class="add_task_form">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ staff_task_form|crispy }}
|
||||||
|
<button type="submit" class="btn btn-success w-100">{% trans 'Save' %}</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock content %}
|
||||||
|
|
||||||
|
{% block customJS %}
|
||||||
|
<script>
|
||||||
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
const noteModal = document.getElementById("noteModal");
|
const noteModal = document.getElementById("noteModal");
|
||||||
const modalTitle = document.getElementById("noteModalLabel");
|
const modalTitle = document.getElementById("noteModalLabel");
|
||||||
|
|
||||||
@ -418,6 +600,128 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
console.error("Error loading form:", error);
|
console.error("Error loading form:", error);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
|
||||||
{% endblock %}
|
let Toast = Swal.mixin({
|
||||||
|
toast: true,
|
||||||
|
position: "top-end",
|
||||||
|
showConfirmButton: false,
|
||||||
|
timer: 3000,
|
||||||
|
timerProgressBar: true,
|
||||||
|
didOpen: (toast) => {
|
||||||
|
toast.onmouseenter = Swal.stopTimer;
|
||||||
|
toast.onmouseleave = Swal.resumeTimer;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Display Django messages
|
||||||
|
{% if messages %}
|
||||||
|
{% for message in messages %}
|
||||||
|
Toast.fire({
|
||||||
|
icon: "{{ message.tags }}",
|
||||||
|
titleText: "{{ message|safe }}"
|
||||||
|
});
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
function openActionModal(leadId, currentAction, nextAction, nextActionDate) {
|
||||||
|
const modal = new bootstrap.Modal(document.getElementById('actionTrackingModal'));
|
||||||
|
document.getElementById('leadId').value = leadId;
|
||||||
|
document.getElementById('currentAction').value = currentAction;
|
||||||
|
document.getElementById('nextAction').value = nextAction;
|
||||||
|
document.getElementById('nextActionDate').value = nextActionDate;
|
||||||
|
modal.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('actionTrackingForm').addEventListener('submit', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
const formData = new FormData(this);
|
||||||
|
|
||||||
|
// Show loading indicator
|
||||||
|
Swal.fire({
|
||||||
|
toast: true,
|
||||||
|
icon: 'info',
|
||||||
|
text: 'Please wait...',
|
||||||
|
allowOutsideClick: false,
|
||||||
|
position: "top-end",
|
||||||
|
showConfirmButton: false,
|
||||||
|
timer: 2000,
|
||||||
|
timerProgressBar: false,
|
||||||
|
didOpen: (toast) => {
|
||||||
|
toast.onmouseenter = Swal.stopTimer;
|
||||||
|
toast.onmouseleave = Swal.resumeTimer;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
fetch("{% url 'update_lead_actions' %}", {
|
||||||
|
method: 'POST',
|
||||||
|
body: formData,
|
||||||
|
headers: {
|
||||||
|
'X-CSRFToken': '{{ csrf_token }}'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
Swal.close();
|
||||||
|
if (data.success) {
|
||||||
|
// Success notification
|
||||||
|
Swal.fire({
|
||||||
|
toast: true,
|
||||||
|
icon: 'success',
|
||||||
|
position: "top-end",
|
||||||
|
text: data.message || 'Actions updated successfully',
|
||||||
|
showConfirmButton: false,
|
||||||
|
timer: 2000,
|
||||||
|
timerProgressBar: false,
|
||||||
|
didOpen: (toast) => {
|
||||||
|
toast.onmouseenter = Swal.stopTimer;
|
||||||
|
toast.onmouseleave = Swal.resumeTimer;
|
||||||
|
}
|
||||||
|
}).then(() => {
|
||||||
|
location.reload(); // Refresh after user clicks OK
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Error notification
|
||||||
|
Swal.fire({
|
||||||
|
toast: true,
|
||||||
|
icon: 'error',
|
||||||
|
position: "top-end",
|
||||||
|
text: data.message || 'Failed to update actions',
|
||||||
|
showConfirmButton: false,
|
||||||
|
timer: 2000,
|
||||||
|
timerProgressBar: false,
|
||||||
|
didOpen: (toast) => {
|
||||||
|
toast.onmouseenter = Swal.stopTimer;
|
||||||
|
toast.onmouseleave = Swal.resumeTimer;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
Swal.close();
|
||||||
|
console.error('Error:', error);
|
||||||
|
Swal.fire({
|
||||||
|
toast: true,
|
||||||
|
icon: 'error',
|
||||||
|
position: "top-end",
|
||||||
|
text: 'An unexpected error occurred',
|
||||||
|
showConfirmButton: false,
|
||||||
|
timer: 2000,
|
||||||
|
timerProgressBar: false,
|
||||||
|
didOpen: (toast) => {
|
||||||
|
toast.onmouseenter = Swal.stopTimer;
|
||||||
|
toast.onmouseleave = Swal.resumeTimer;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Helper function for notifications
|
||||||
|
function notify(tag, msg) {
|
||||||
|
Toast.fire({
|
||||||
|
icon: tag,
|
||||||
|
titleText: msg
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
{% endblock customJS %}
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
{% load i18n static crispy_forms_filters %}
|
{% load i18n static crispy_forms_filters %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<h1>{% if object %}{{ _("Update") }}{% else %}{{ _("Create") }}{% endif %}</h1>
|
<h1>{% if object %}{{ _("Update") }}{% else %}{{ _("Create") }}{% endif %}</h1>
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<div class="col-sm-6 col-md-8">
|
<div class="col-sm-6 col-md-8">
|
||||||
@ -18,5 +18,5 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -1,9 +1,9 @@
|
|||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
{% load i18n static %}
|
{% load i18n static humanize %}
|
||||||
{% block title %}{{ _('Leads')|capfirst }}{% endblock title %}
|
{% block title %}{{ _('Leads')|capfirst }}{% endblock title %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row g-3">
|
<div class="row g-3">
|
||||||
<h2 class="mb-4">{{ _("Leads")|capfirst }}</h2>
|
<h2 class="mb-4">{{ _("Leads")|capfirst }}</h2>
|
||||||
<!-- Action Tracking Modal -->
|
<!-- Action Tracking Modal -->
|
||||||
<div class="modal fade" id="actionTrackingModal" tabindex="-1" aria-labelledby="actionTrackingModalLabel" aria-hidden="true">
|
<div class="modal fade" id="actionTrackingModal" tabindex="-1" aria-labelledby="actionTrackingModalLabel" aria-hidden="true">
|
||||||
@ -112,19 +112,7 @@
|
|||||||
<th class="align-middle white-space-nowrap text-uppercase" scope="col" style="width: 10%;">
|
<th class="align-middle white-space-nowrap text-uppercase" scope="col" style="width: 10%;">
|
||||||
<div class="d-inline-flex flex-center">
|
<div class="d-inline-flex flex-center">
|
||||||
<div class="d-flex align-items-center bg-info-subtle rounded me-2"><span class="text-info-dark" data-feather="database"></span></div>
|
<div class="d-flex align-items-center bg-info-subtle rounded me-2"><span class="text-info-dark" data-feather="database"></span></div>
|
||||||
<span>{{ _("Current Action")|capfirst }}</span>
|
<span>{{ _("Action")|capfirst }}</span>
|
||||||
</div>
|
|
||||||
</th>
|
|
||||||
<th class="align-middle white-space-nowrap text-uppercase" scope="col" style="width: 10%;">
|
|
||||||
<div class="d-inline-flex flex-center">
|
|
||||||
<div class="d-flex align-items-center bg-info-subtle rounded me-2"><span class="text-info-dark" data-feather="database"></span></div>
|
|
||||||
<span>{{ _("Next Action")|capfirst }}</span>
|
|
||||||
</div>
|
|
||||||
</th>
|
|
||||||
<th class="align-middle white-space-nowrap text-uppercase" scope="col" style="width: 10%;">
|
|
||||||
<div class="d-inline-flex flex-center">
|
|
||||||
<div class="d-flex align-items-center bg-info-subtle rounded me-2"><span class="text-info-dark" data-feather="database"></span></div>
|
|
||||||
<span>{{ _("Next Action Date")|capfirst }}</span>
|
|
||||||
</div>
|
</div>
|
||||||
</th>
|
</th>
|
||||||
<th class="align-middle white-space-nowrap text-uppercase" scope="col" style="width: 10%;">
|
<th class="align-middle white-space-nowrap text-uppercase" scope="col" style="width: 10%;">
|
||||||
@ -133,32 +121,15 @@
|
|||||||
<span>{{ _("Assigned To")|capfirst }}</span>
|
<span>{{ _("Assigned To")|capfirst }}</span>
|
||||||
</div>
|
</div>
|
||||||
</th>
|
</th>
|
||||||
<th class="align-middle white-space-nowrap text-uppercase" scope="col" style="width: 10%;">
|
|
||||||
<div class="d-inline-flex flex-center">
|
|
||||||
<div class="d-flex align-items-center bg-info-subtle rounded me-2"><span class="text-info-dark" data-feather="database"></span></div>
|
|
||||||
<span>{{ _("Source")|capfirst }}</span>
|
|
||||||
</div>
|
|
||||||
</th>
|
|
||||||
<th class="align-middle white-space-nowrap text-uppercase" scope="col" style="width: 10%;">
|
<th class="align-middle white-space-nowrap text-uppercase" scope="col" style="width: 10%;">
|
||||||
<div class="d-inline-flex flex-center">
|
<div class="d-inline-flex flex-center">
|
||||||
<div class="d-flex align-items-center bg-warning-subtle rounded me-2"><span class="text-warning-dark" data-feather="grid"></span></div>
|
<div class="d-flex align-items-center bg-warning-subtle rounded me-2"><span class="text-warning-dark" data-feather="grid"></span></div>
|
||||||
<span>{{ _("Channel")|capfirst }}</span>
|
<span>{{ _("Opportunity")|capfirst }}</span>
|
||||||
</div>
|
|
||||||
</th>
|
|
||||||
<th class="align-middle white-space-nowrap text-uppercase" scope="col" style="width: 10%;">
|
|
||||||
<div class="d-inline-flex flex-center">
|
|
||||||
<div class="d-flex align-items-center bg-warning-subtle rounded me-2"><span class="text-warning-dark" data-feather="grid"></span></div>
|
|
||||||
<span>{{ _("Stage")|capfirst }}</span>
|
|
||||||
</div>
|
|
||||||
</th>
|
|
||||||
<th class="align-middle white-space-nowrap text-uppercase" scope="col" style="width: 10%;">
|
|
||||||
<div class="d-inline-flex flex-center">
|
|
||||||
<div class="d-flex align-items-center bg-warning-subtle rounded me-2"><span class="text-warning-dark" data-feather="grid"></span></div>
|
|
||||||
<span>{{ _("Is Opportunity")|capfirst }}</span>
|
|
||||||
</div>
|
</div>
|
||||||
</th>
|
</th>
|
||||||
<th class="align-middle white-space-nowrap text-uppercase" scope="col" style="width: 15%;">
|
<th class="align-middle white-space-nowrap text-uppercase" scope="col" style="width: 15%;">
|
||||||
{{ _("Create date") }}
|
{{ _("Action") }}
|
||||||
</th>
|
</th>
|
||||||
<th class="text-end white-space-nowrap align-middle" scope="col"></th>
|
<th class="text-end white-space-nowrap align-middle" scope="col"></th>
|
||||||
</tr>
|
</tr>
|
||||||
@ -230,15 +201,15 @@
|
|||||||
{% if schedule.scheduled_type == "call" %}
|
{% if schedule.scheduled_type == "call" %}
|
||||||
<a href="{% url 'appointment:get_user_appointments' %}">
|
<a href="{% url 'appointment:get_user_appointments' %}">
|
||||||
<span class="badge badge-phoenix badge-phoenix-primary text-primary {% if schedule.schedule_past_date %}badge-phoenix-danger text-danger{% endif %} fw-semibold"><span class="text-primary {% if schedule.schedule_past_date %}text-danger{% endif %}" data-feather="phone"></span>
|
<span class="badge badge-phoenix badge-phoenix-primary text-primary {% if schedule.schedule_past_date %}badge-phoenix-danger text-danger{% endif %} fw-semibold"><span class="text-primary {% if schedule.schedule_past_date %}text-danger{% endif %}" data-feather="phone"></span>
|
||||||
{{ schedule.scheduled_at }}</span></a>
|
{{ schedule.scheduled_at|naturalday|capfirst }}</span></a>
|
||||||
{% elif schedule.scheduled_type == "meeting" %}
|
{% elif schedule.scheduled_type == "meeting" %}
|
||||||
<a href="{% url 'appointment:get_user_appointments' %}">
|
<a href="{% url 'appointment:get_user_appointments' %}">
|
||||||
<span class="badge badge-phoenix badge-phoenix-success text-success fw-semibold"><span class="text-success" data-feather="calendar"></span>
|
<span class="badge badge-phoenix badge-phoenix-success text-success fw-semibold"><span class="text-success" data-feather="calendar"></span>
|
||||||
{{ schedule.scheduled_at }}</span></a>
|
{{ schedule.scheduled_at|naturalday|capfirst }}</span></a>
|
||||||
{% elif schedule.scheduled_type == "email" %}
|
{% elif schedule.scheduled_type == "email" %}
|
||||||
<a href="{% url 'appointment:get_user_appointments' %}">
|
<a href="{% url 'appointment:get_user_appointments' %}">
|
||||||
<span class="badge badge-phoenix badge-phoenix-warning text-warning fw-semibold"><span class="text-warning" data-feather="email"></span>
|
<span class="badge badge-phoenix badge-phoenix-warning text-warning fw-semibold"><span class="text-warning" data-feather="email"></span>
|
||||||
{{ schedule.scheduled_at }}</span></a>
|
{{ schedule.scheduled_at|naturalday|capfirst }}</span></a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@ -255,12 +226,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="align-middle white-space-nowrap text-body-tertiary text-opacity-85 fw-semibold text-body-highlight">{{ lead.get_status|upper }}</td>
|
<td class="align-middle white-space-nowrap text-body-tertiary text-opacity-85 fw-semibold text-body-highlight">{{ lead.get_status|upper }}</td>
|
||||||
<td class="align-middle white-space-nowrap text-body-tertiary text-opacity-85 fw-semibold text-body-highlight">{% if lead.next_action %}{{ lead.next_action|upper }}{% endif %}</td>
|
|
||||||
<td class="align-middle white-space-nowrap text-body-tertiary text-opacity-85 fw-semibold text-body-highlight">{% if lead.next_action %}{{ lead.next_action_date|upper }}{% endif %}</td>
|
|
||||||
<td class="align-middle white-space-nowrap text-body-tertiary text-opacity-85 fw-semibold text-body-highlight">{{ lead.staff|upper }}</td>
|
<td class="align-middle white-space-nowrap text-body-tertiary text-opacity-85 fw-semibold text-body-highlight">{{ lead.staff|upper }}</td>
|
||||||
<td class="align-middle white-space-nowrap fw-semibold text-body-highlight">{{ lead.source|upper }}</td>
|
{% comment %} <td class="align-middle white-space-nowrap text-body-tertiary text-opacity-85 fw-semibold text-body-highlight">
|
||||||
<td class="align-middle white-space-nowrap text-body-tertiary text-opacity-85 fw-semibold text-body-highlight">{{ lead.channel|upper }}</td>
|
|
||||||
<td class="align-middle white-space-nowrap text-body-tertiary text-opacity-85 fw-semibold text-body-highlight">
|
|
||||||
{% if lead.opportunity.stage == "prospect" %}
|
{% if lead.opportunity.stage == "prospect" %}
|
||||||
<span class="badge text-bg-primary">{{ lead.opportunity.stage|upper }}</span>
|
<span class="badge text-bg-primary">{{ lead.opportunity.stage|upper }}</span>
|
||||||
{% elif lead.opportunity.stage == "proposal" %}
|
{% elif lead.opportunity.stage == "proposal" %}
|
||||||
@ -272,14 +239,12 @@
|
|||||||
{% elif lead.opportunity.stage == "closed_lost" %}
|
{% elif lead.opportunity.stage == "closed_lost" %}
|
||||||
<span class="badge text-bg-danger">{{ lead.opportunity.stage|upper }}</span>
|
<span class="badge text-bg-danger">{{ lead.opportunity.stage|upper }}</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td> {% endcomment %}
|
||||||
<td class="align-middle white-space-nowrap text-body-tertiary text-opacity-85 fw-semibold text-body-highlight">
|
<td class="align-middle white-space-nowrap text-body-tertiary text-opacity-85 fw-semibold text-body-highlight">
|
||||||
{% if lead.opportunity %}
|
{% if lead.opportunity %}
|
||||||
<a href="{% url 'opportunity_detail' lead.opportunity.id %}">
|
<a href="{% url 'opportunity_detail' lead.opportunity.id %}">
|
||||||
<span class="badge badge-phoenix badge-phoenix-success">View Details <i class="fa-solid fa-arrow-up-right-from-square"></i></span>
|
<span class="badge badge-phoenix badge-phoenix-success">Opportunity {{ lead.opportunity.lead}} <i class="fa-solid fa-arrow-up-right-from-square"></i></span>
|
||||||
</a>
|
</a>
|
||||||
{% else %}
|
|
||||||
<span class="badge badge-phoenix badge-phoenix-danger">{{ _("No") }}</span>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td class="align-middle white-space-nowrap text-end">
|
<td class="align-middle white-space-nowrap text-end">
|
||||||
@ -363,13 +328,13 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block customJS %}
|
{% block customJS %}
|
||||||
<script>
|
<script>
|
||||||
// Initialize SweetAlert Toast for general messages
|
// Initialize SweetAlert Toast for general messages
|
||||||
let Toast = Swal.mixin({
|
let Toast = Swal.mixin({
|
||||||
toast: true,
|
toast: true,
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
{% block title %}{{ _("Leads") }}{% endblock title %}
|
{% block title %}{{ _("Leads") }}{% endblock title %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="card email-content">
|
<div class="card email-content">
|
||||||
<h5 class="card-header">Send Mail</h5>
|
<h5 class="card-header">Send Mail</h5>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<form class="d-flex flex-column h-100" action="{% url 'send_lead_email' lead.pk %}" method="post">
|
<form class="d-flex flex-column h-100" action="{% url 'send_lead_email' lead.pk %}" method="post">
|
||||||
@ -34,7 +34,7 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
@ -3,7 +3,7 @@
|
|||||||
{% block title %}{{ _('Leads')|capfirst }}{% endblock title %}
|
{% block title %}{{ _('Leads')|capfirst }}{% endblock title %}
|
||||||
|
|
||||||
{% block customCSS %}
|
{% block customCSS %}
|
||||||
<style>
|
<style>
|
||||||
.kanban-column {
|
.kanban-column {
|
||||||
background-color: #f8f9fa;
|
background-color: #f8f9fa;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
@ -42,7 +42,23 @@
|
|||||||
.lead-card small {
|
.lead-card small {
|
||||||
color: #6c757d;
|
color: #6c757d;
|
||||||
}
|
}
|
||||||
</style>
|
.bg-success-soft {
|
||||||
|
background-color: rgba(17, 240, 66, 0.1) !important;
|
||||||
|
opacity: .8;
|
||||||
|
}
|
||||||
|
.bg-danger-soft {
|
||||||
|
background-color: rgba(230, 50, 68, 0.1) !important;
|
||||||
|
opacity: .8;
|
||||||
|
}
|
||||||
|
.bg-info-soft {
|
||||||
|
background-color: rgba(41, 197, 245, 0.1) !important;
|
||||||
|
opacity: .8;
|
||||||
|
}
|
||||||
|
.bg-negotiation-soft {
|
||||||
|
background-color: rgba(113, 206, 206, 0.1) !important;
|
||||||
|
opacity: .8;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
{% endblock customCSS %}
|
{% endblock customCSS %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container-fluid my-4">
|
<div class="container-fluid my-4">
|
||||||
@ -51,7 +67,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row g-3">
|
<div class="row g-3">
|
||||||
<!-- Column Template -->
|
<!-- New Lead -->
|
||||||
<div class="col-md">
|
<div class="col-md">
|
||||||
<div class="kanban-column">
|
<div class="kanban-column">
|
||||||
<div class="kanban-header">New Leads ({{new|length}})</div>
|
<div class="kanban-header">New Leads ({{new|length}})</div>
|
||||||
@ -83,38 +99,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Under Review -->
|
|
||||||
<div class="col-md">
|
|
||||||
<div class="kanban-column">
|
|
||||||
<div class="kanban-header">Won ({{won|length}})</div>
|
|
||||||
{% for lead in won %}
|
|
||||||
<a href="{% url 'lead_detail' lead.id %}">
|
|
||||||
<div class="lead-card">
|
|
||||||
<strong>{{lead.full_name|capfirst}}</strong><br>
|
|
||||||
<small>{{lead.email}}</small><br>
|
|
||||||
<small>{{lead.phone_number}}</small>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Demo -->
|
|
||||||
<div class="col-md">
|
|
||||||
<div class="kanban-column">
|
|
||||||
<div class="kanban-header">Lose ({{lose|length}})</div>
|
|
||||||
{% for lead in lose %}
|
|
||||||
<a href="{% url 'lead_detail' lead.id %}">
|
|
||||||
<div class="lead-card">
|
|
||||||
<strong>{{lead.full_name|capfirst}}</strong><br>
|
|
||||||
<small>{{lead.email}}</small><br>
|
|
||||||
<small>{{lead.phone_number}}</small>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Negotiation -->
|
<!-- Negotiation -->
|
||||||
<div class="col-md">
|
<div class="col-md">
|
||||||
<div class="kanban-column">
|
<div class="kanban-column">
|
||||||
@ -130,6 +114,39 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Won -->
|
||||||
|
<div class="col-md">
|
||||||
|
<div class="kanban-column">
|
||||||
|
<div class="kanban-header">Won ({{won|length}})</div>
|
||||||
|
{% for lead in won %}
|
||||||
|
<a href="{% url 'lead_detail' lead.id %}">
|
||||||
|
<div class="lead-card">
|
||||||
|
<strong>{{lead.full_name|capfirst}}</strong><br>
|
||||||
|
<small>{{lead.email}}</small><br>
|
||||||
|
<small>{{lead.phone_number}}</small>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Lose -->
|
||||||
|
<div class="col-md">
|
||||||
|
<div class="kanban-column">
|
||||||
|
<div class="kanban-header">Lose ({{lose|length}})</div>
|
||||||
|
{% for lead in lose %}
|
||||||
|
<a href="{% url 'lead_detail' lead.id %}">
|
||||||
|
<div class="lead-card">
|
||||||
|
<strong>{{lead.full_name|capfirst}}</strong><br>
|
||||||
|
<small>{{lead.email}}</small><br>
|
||||||
|
<small>{{lead.phone_number}}</small>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -20,9 +20,9 @@
|
|||||||
color: #aaa;
|
color: #aaa;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
{% endblock customCSS %}
|
{% endblock customCSS %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<!-- Welcome Row -->
|
<!-- Welcome Row -->
|
||||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||||
|
|||||||
@ -2,8 +2,8 @@
|
|||||||
{% load i18n static crispy_forms_filters %}
|
{% load i18n static crispy_forms_filters %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h3>{% if object %}{{ _("Update") }}{% else %}{{ _("Create") }}{% endif %}</h3>
|
<h3>{% if object %}{{ _("Update") }}{% else %}{{ _("Create") }}{% endif %}</h3>
|
||||||
<form method="post">
|
<form method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{{ form|crispy }}
|
{{ form|crispy }}
|
||||||
<button
|
<button
|
||||||
@ -17,5 +17,5 @@
|
|||||||
<a href="{% url 'lead_list' %}" class="btn btn-phoenix-secondary">
|
<a href="{% url 'lead_list' %}" class="btn btn-phoenix-secondary">
|
||||||
{{ _("Cancel") }}
|
{{ _("Cancel") }}
|
||||||
</a>
|
</a>
|
||||||
</form>
|
</form>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -2,16 +2,16 @@
|
|||||||
|
|
||||||
{% if form.instance.pk %}
|
{% if form.instance.pk %}
|
||||||
<form method="post" action="{% url 'update_note_to_lead' note.pk %}" enctype="multipart/form-data">
|
<form method="post" action="{% url 'update_note_to_lead' note.pk %}" enctype="multipart/form-data">
|
||||||
{% else %}
|
{% else %}
|
||||||
<form method="post" action="{% url 'add_note_to_lead' lead.pk %}" enctype="multipart/form-data">
|
<form method="post" action="{% url 'add_note_to_lead' lead.pk %}" enctype="multipart/form-data">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{{ form|crispy }}
|
{{ form|crispy }}
|
||||||
|
|
||||||
{% if form.instance.pk %}
|
{% if form.instance.pk %}
|
||||||
<button type="submit" class="btn btn-sm btn-primary w-100">{{ _("Update") }}</button>
|
<button type="submit" class="btn btn-sm btn-primary w-100">{{ _("Update") }}</button>
|
||||||
{% else %}
|
{% else %}
|
||||||
<button type="submit" class="btn btn-sm btn-success w-100">{{ _("Add") }}</button>
|
<button type="submit" class="btn btn-sm btn-success w-100">{{ _("Add") }}</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@ -31,4 +31,4 @@
|
|||||||
<div class="my-2 text-center fw-bold fs-10 text-body-tertiary text-opactity-85"><a class="fw-bolder" href="{% url 'notifications_history' %}">Notification history</a></div>
|
<div class="my-2 text-center fw-bold fs-10 text-body-tertiary text-opactity-85"><a class="fw-bolder" href="{% url 'notifications_history' %}">Notification history</a></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<h2 class="mb-5">{{ _("Notifications") }}</h2>
|
<h2 class="mb-5">{{ _("Notifications") }}</h2>
|
||||||
|
|
||||||
{% if notifications %}
|
{% if notifications %}
|
||||||
<div class="mx-n4 mx-lg-n6 mb-5 border-bottom">
|
<div class="mx-n4 mx-lg-n6 mb-5 border-bottom">
|
||||||
{% for notification in notifications %}
|
{% for notification in notifications %}
|
||||||
<div class="d-flex align-items-center justify-content-between py-3 px-lg-6 px-4 notification-card border-top">
|
<div class="d-flex align-items-center justify-content-between py-3 px-lg-6 px-4 notification-card border-top">
|
||||||
@ -27,7 +27,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="pagination">
|
<div class="pagination">
|
||||||
<span class="step-links">
|
<span class="step-links">
|
||||||
{% if notifications.has_previous %}
|
{% if notifications.has_previous %}
|
||||||
@ -45,9 +45,9 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<p>No notifications found.</p>
|
<p>No notifications found.</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>Delete Opportunity</h1>
|
<h1>Delete Opportunity</h1>
|
||||||
<p>Are you sure you want to delete "{{ object.deal_name }}"?</p>
|
<p>Are you sure you want to delete "{{ object.deal_name }}"?</p>
|
||||||
<form method="post">
|
<form method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<button type="submit">Yes, delete</button>
|
<button type="submit">Yes, delete</button>
|
||||||
<a href="{% url 'opportunity_list' %}">Cancel</a>
|
<a href="{% url 'opportunity_list' %}">Cancel</a>
|
||||||
</form>
|
</form>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -1,5 +1,5 @@
|
|||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
{% load i18n static %}
|
{% load i18n static humanize %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row align-items-center justify-content-between g-3 mb-4">
|
<div class="row align-items-center justify-content-between g-3 mb-4">
|
||||||
@ -18,7 +18,8 @@
|
|||||||
<a class="dropdown-item" href="{% url 'estimate_create_from_opportunity' opportunity.pk %}">{{ _("Create Quotation")}}</a>
|
<a class="dropdown-item" href="{% url 'estimate_create_from_opportunity' opportunity.pk %}">{{ _("Create Quotation")}}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</li>
|
</li>
|
||||||
<li><a class="dropdown-item text-danger" href="">Delete Lead</a></li>
|
<li><a class="dropdown-item" href="{% url 'update_opportunity' opportunity.pk %}">Update Opportunity</a></li>
|
||||||
|
<li><a class="dropdown-item text-danger" href="">Delete Opportunity</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -169,9 +170,9 @@
|
|||||||
<p class="fw-bold mb-0">{{ _("Estimated Revenue") }}</p>
|
<p class="fw-bold mb-0">{{ _("Estimated Revenue") }}</p>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="py-2 d-none d-sm-block pe-sm-2">:{{opportunity.estimate.get_revenue_estimate}}</td>
|
<td class="py-2 d-none d-sm-block pe-sm-2">:</td>
|
||||||
<td class="py-2">
|
<td class="py-2">
|
||||||
<p class="ps-6 ps-sm-0 fw-semibold mb-0">{{ opportunity.car.finances.revenue }}</p>
|
<p class="ps-6 ps-sm-0 fw-semibold mb-0"><span class="currency">{{CURRENCY}}</span>{{ opportunity.expected_revenue }}</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
@ -296,7 +297,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-auto">
|
<div class="col-auto">
|
||||||
<button class="btn btn-phoenix-primary px-6">Add Activity</button>
|
<button class="btn btn-phoenix-primary btn-sm" type="button" data-bs-toggle="modal" data-bs-target="#activityModal"><span class="fas fa-plus me-1"></span>{{ _("Add Activity") }}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% for activity in activities %}
|
{% for activity in activities %}
|
||||||
@ -307,7 +308,7 @@
|
|||||||
<span class="fa-solid fa-phone text-warning fs-8"></span>
|
<span class="fa-solid fa-phone text-warning fs-8"></span>
|
||||||
{% elif activity.activity_type == "email" %}
|
{% elif activity.activity_type == "email" %}
|
||||||
<span class="fa-solid fa-envelope text-info-light fs-8"></span>
|
<span class="fa-solid fa-envelope text-info-light fs-8"></span>
|
||||||
{% elif activity.activity_type == "visit" %}
|
{% elif activity.activity_type == "meeting" %}
|
||||||
<span class="fa-solid fa-users text-danger fs-8"></span>
|
<span class="fa-solid fa-users text-danger fs-8"></span>
|
||||||
{% elif activity.activity_type == "whatsapp" %}
|
{% elif activity.activity_type == "whatsapp" %}
|
||||||
<span class="fab fa-whatsapp text-success-dark fs-7"></span>
|
<span class="fab fa-whatsapp text-success-dark fs-7"></span>
|
||||||
@ -319,7 +320,7 @@
|
|||||||
<h5 class="text-body-highlight lh-sm"></h5>
|
<h5 class="text-body-highlight lh-sm"></h5>
|
||||||
<p class="fs-9 mb-0">by<a class="ms-1" href="#!">{{activity.created_by}}</a></p>
|
<p class="fs-9 mb-0">by<a class="ms-1" href="#!">{{activity.created_by}}</a></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="fs-9"><span class="fa-regular fa-calendar-days text-primary me-2"></span><span class="fw-semibold">{{activity.created}}</span></div>
|
<div class="fs-9"><span class="fa-regular fa-calendar-days text-primary me-2"></span><span class="fw-semibold">{{activity.created|naturalday|capfirst}}</span></div>
|
||||||
</div>
|
</div>
|
||||||
<p class="fs-9 mb-0"></p>
|
<p class="fs-9 mb-0"></p>
|
||||||
</div>
|
</div>
|
||||||
@ -552,4 +553,5 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% include "components/activity_modal.html" with content_type="opportunity" pk=opportunity.pk %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -1,95 +1,203 @@
|
|||||||
{% extends "base.html" %} <!-- Assuming you have a base template -->
|
{% extends 'base.html' %}
|
||||||
{% load i18n %} <!-- Load the internationalization template tags -->
|
{% load i18n static widget_tweaks custom_filters %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row g-3 mb-4 align-items-center">
|
||||||
|
<div class="col">
|
||||||
|
<h2 class="mb-0">
|
||||||
|
{% if form.instance.pk %}
|
||||||
|
{% trans "Edit Opportunity" %}
|
||||||
|
{% else %}
|
||||||
|
{% trans "Create New Opportunity" %}
|
||||||
|
{% endif %}
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<div class="col-auto">
|
||||||
|
<a href="{% url 'opportunity_list' %}" class="btn btn-phoenix-secondary">
|
||||||
|
<span class="fas fa-arrow-left me-2"></span>{% trans "Back to list" %}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="row g-3">
|
<div class="row g-3">
|
||||||
<div class="col-sm-6 col-md-8">
|
<div class="col-lg-8">
|
||||||
<h2>{% if form.instance.pk %}{{ _("Edit Opportunity") }}{% else %}{{ _("Add New Opportunity") }}{% endif %}</h2>
|
<div class="card">
|
||||||
</div>
|
<div class="card-body p-4 p-sm-5">
|
||||||
<div class="col-sm-6 col-md-8">
|
<form method="post" enctype="multipart/form-data">
|
||||||
<form class="row g-3" method="post" class="form" novalidate>
|
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
|
||||||
<!-- Customer -->
|
{% if form.non_field_errors %}
|
||||||
<div class="col-sm-6 col-md-4">
|
<div class="alert alert-danger">
|
||||||
<div class="form-floating">
|
{{ form.non_field_errors }}
|
||||||
<select class="form-control" id="{{ form.customer.id_for_label }}" name="{{ form.customer.name }}">
|
|
||||||
{% for value, label in form.customer.field.choices %}
|
|
||||||
<option value="{{ value }}" {% if form.customer.value == value %}selected{% endif %}>{{ label }}</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
<label for="{{ form.customer.id_for_label }}">{{ _("Customer") }}</label>
|
|
||||||
</div>
|
</div>
|
||||||
{{ form.customer.errors }}
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- Lead Field -->
|
||||||
|
<div class="mb-4">
|
||||||
|
<label class="form-label" for="{{ form.lead.id_for_label }}">
|
||||||
|
{{ form.lead.label }}
|
||||||
|
<span class="text-danger">*</span>
|
||||||
|
</label>
|
||||||
|
{{ form.lead|add_class:"form-control" }}
|
||||||
|
{% if form.lead.errors %}
|
||||||
|
<div class="invalid-feedback d-block">
|
||||||
|
{{ form.lead.errors }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Car -->
|
<!-- Car Field -->
|
||||||
<div class="col-sm-6 col-md-4">
|
<div class="mb-4">
|
||||||
<div class="form-floating">
|
<label class="form-label" for="{{ form.car.id_for_label }}">
|
||||||
<select class="form-control" id="{{ form.car.id_for_label }}" name="{{ form.car.name }}">
|
{{ form.car.label }}
|
||||||
{% for value, label in form.car.field.choices %}
|
<span class="text-danger">*</span>
|
||||||
<option value="{{ value }}" {% if form.car.value == value %}selected{% endif %}>{{ label }}</option>
|
</label>
|
||||||
{% endfor %}
|
{{ form.car|add_class:"form-control" }}
|
||||||
</select>
|
{% if form.car.errors %}
|
||||||
<label for="{{ form.car.id_for_label }}">{{ _("Car") }}</label>
|
<div class="invalid-feedback d-block">
|
||||||
</div>
|
|
||||||
{{ form.car.errors }}
|
{{ form.car.errors }}
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
<!-- Stage -->
|
|
||||||
<div class="col-sm-6 col-md-4">
|
|
||||||
<div class="form-floating">
|
|
||||||
<select class="form-control" id="{{ form.stage.id_for_label }}" name="{{ form.stage.name }}">
|
|
||||||
{% for value, label in form.stage.field.choices %}
|
|
||||||
<option value="{{ value }}" {% if form.stage.value == value %}selected{% endif %}>{{ label }}</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
<label for="{{ form.stage.id_for_label }}">{{ _("Stage") }}</label>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Stage Field -->
|
||||||
|
<div class="mb-4">
|
||||||
|
<label class="form-label" for="{{ form.stage.id_for_label }}">
|
||||||
|
{{ form.stage.label }}
|
||||||
|
<span class="text-danger">*</span>
|
||||||
|
</label>
|
||||||
|
{{ form.stage|add_class:"form-control" }}
|
||||||
|
{% if form.stage.errors %}
|
||||||
|
<div class="invalid-feedback d-block">
|
||||||
{{ form.stage.errors }}
|
{{ form.stage.errors }}
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
<!-- Probability -->
|
|
||||||
<div class="col-sm-6 col-md-4">
|
|
||||||
<div class="form-floating">
|
|
||||||
<input type="number" class="form-control" id="{{ form.probability.id_for_label }}" name="{{ form.probability.name }}" value="{{ form.probability.value|default:'' }}" placeholder="{{ _('Enter probability') }}">
|
|
||||||
<label for="{{ form.probability.id_for_label }}">{{ _("Probability") }}</label>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Probability Field -->
|
||||||
|
<div class="mb-4">
|
||||||
|
<label class="form-label" for="{{ form.probability.id_for_label }}">
|
||||||
|
{{ form.probability.label }}
|
||||||
|
<span class="text-danger">*</span>
|
||||||
|
</label>
|
||||||
|
<div class="d-flex align-items-center gap-3">
|
||||||
|
<input type="range"
|
||||||
|
name="{{ form.probability.name }}"
|
||||||
|
id="{{ form.probability.id_for_label }}"
|
||||||
|
min="0" max="100" step="1"
|
||||||
|
value="{{ form.probability.value|default:'50' }}"
|
||||||
|
class="form-control form-range"
|
||||||
|
oninput="updateProbabilityValue(this.value)">
|
||||||
|
<span id="probability-value" class="badge badge-phoenix fs-6 badge-phoenix-primary">
|
||||||
|
{{ form.probability.value|default:'50' }}%
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{% if form.probability.errors %}
|
||||||
|
<div class="invalid-feedback d-block">
|
||||||
{{ form.probability.errors }}
|
{{ form.probability.errors }}
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
<!-- Staff -->
|
|
||||||
<div class="col-sm-6 col-md-4">
|
|
||||||
<div class="form-floating">
|
|
||||||
<select class="form-control" id="{{ form.staff.id_for_label }}" name="{{ form.staff.name }}">
|
|
||||||
{% for value, label in form.staff.field.choices %}
|
|
||||||
<option value="{{ value }}" {% if form.staff.value == value %}selected{% endif %}>{{ label }}</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
<label for="{{ form.staff.id_for_label }}">{{ _("Staff") }}</label>
|
|
||||||
</div>
|
|
||||||
{{ form.staff.errors }}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- closing date-->
|
<!-- Expected Revenue -->
|
||||||
<div class="col-sm-6 col-md-4">
|
<div class="mb-4">
|
||||||
<div class="form-floating">
|
<label class="form-label" for="{{ form.expected_revenue.id_for_label }}">
|
||||||
<input type="date" class="form-control" id="{{ form.closing_date.id_for_label }}" name="{{ form.closing_date.name }}" value="{{ form.closing_date.value|date:'Y-m-d' }}">
|
{{ form.expected_revenue.label }}
|
||||||
<label for="{{ form.closing_date.id_for_label }}">{{ _("Closing Date")}}</label>
|
</label>
|
||||||
|
<div class="input-group">
|
||||||
|
<span class="input-group-text"><span class="currency">{{CURRENCY}}</span></span>
|
||||||
|
{{ form.expected_revenue|add_class:"form-control" }}
|
||||||
|
</div>
|
||||||
|
{% if form.expected_revenue.errors %}
|
||||||
|
<div class="invalid-feedback d-block">
|
||||||
|
{{ form.expected_revenue.errors }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Closing Date -->
|
||||||
|
<div class="mb-5">
|
||||||
|
<label class="form-label" for="{{ form.closing_date.id_for_label }}">
|
||||||
|
{{ form.closing_date.label }}
|
||||||
|
</label>
|
||||||
|
<div class="input-group">
|
||||||
|
{{ form.closing_date|add_class:"form-control" }}
|
||||||
|
<span class="input-group-text"><span class="far fa-calendar"></span></span>
|
||||||
|
</div>
|
||||||
|
{% if form.closing_date.errors %}
|
||||||
|
<div class="invalid-feedback d-block">
|
||||||
{{ form.closing_date.errors }}
|
{{ form.closing_date.errors }}
|
||||||
</div>
|
</div>
|
||||||
{{ form.closing_date.errors }}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Buttons -->
|
<!-- Form Actions -->
|
||||||
<div class="row mt-4">
|
<div class="d-flex justify-content-end gap-3">
|
||||||
<div class="col-sm-12">
|
<button type="reset" class="btn btn-phoenix-danger px-4">
|
||||||
<button type="submit" class="btn btn-primary">{{ _("Save") }}</button>
|
<span class="fas fa-redo me-2"></span>{% trans "Reset" %}
|
||||||
<a href="{% url 'opportunity_list' %}" class="btn btn-secondary">{{ _("Cancel") }}</a>
|
</button>
|
||||||
|
<button type="submit" class="btn btn-phoenix-primary px-6">
|
||||||
|
{% if form.instance.pk %}
|
||||||
|
<span class="fas fa-save me-2"></span>{% trans "Update" %}
|
||||||
|
{% else %}
|
||||||
|
<span class="fas fa-plus me-2"></span>{% trans "Create" %}
|
||||||
|
{% endif %}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</div>
|
||||||
|
<div class="col-lg-4">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body p-4">
|
||||||
|
<h4 class="mb-3">{% trans "Opportunity Guidelines" %}</h4>
|
||||||
|
<ul class="nav flex-column gap-2 nav-guide">
|
||||||
|
<li class="nav-item">
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<span class="fas fa-circle text-primary fs-11 me-2"></span>
|
||||||
|
<span class="text-body-highlight">{% trans "Probability indicates conversion chance" %}</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<span class="fas fa-circle text-warning fs-11 me-2"></span>
|
||||||
|
<span class="text-body-highlight">{% trans "Update stage as deal progresses" %}</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<span class="fas fa-circle text-success fs-11 me-2"></span>
|
||||||
|
<span class="text-body-highlight">{% trans "Set realistic closing dates" %}</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function updateProbabilityValue(value) {
|
||||||
|
const badge = document.getElementById('probability-value');
|
||||||
|
badge.textContent = value + '%';
|
||||||
|
|
||||||
|
// Update badge color based on value
|
||||||
|
if (value >= 75) {
|
||||||
|
badge.className = 'badge badge-phoenix fs-6 badge-phoenix-success';
|
||||||
|
} else if (value >= 50) {
|
||||||
|
badge.className = 'badge badge-phoenix fs-6 badge-phoenix-warning';
|
||||||
|
} else {
|
||||||
|
badge.className = 'badge badge-phoenix fs-6 badge-phoenix-danger';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize on load
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const rangeInput = document.getElementById('{{ form.probability.id_for_label }}');
|
||||||
|
updateProbabilityValue(rangeInput.value);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -47,7 +47,7 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
<span class="me-2" data-feather="clock" style="stroke-width:2;"></span>
|
<span class="me-2" data-feather="clock" style="stroke-width:2;"></span>
|
||||||
<p class="mb-0 fs-9 fw-semibold text-body-tertiary date">{{ opportunity.created|date }}<span class="text-body-quaternary"> . {{ opportunity.created|time}}</span></p>
|
<p class="mb-0 fs-9 fw-semibold text-body-tertiary date">{{ opportunity.created|date }}<span class="text-body-quaternary"> . {{ opportunity.created|time}}</span></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -131,7 +131,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal fade" id="deleteModal"
|
<div class="modal fade" id="deleteModal"
|
||||||
data-bs-backdrop="static"
|
data-bs-backdrop="static"
|
||||||
data-bs-keyboard="false"
|
data-bs-keyboard="false"
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
@ -161,8 +161,8 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal fade" id="addOpportunityModal" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="addOpportunityModalLabel" aria-hidden="true">
|
<div class="modal fade" id="addOpportunityModal" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="addOpportunityModalLabel" aria-hidden="true">
|
||||||
<div class="modal-dialog modal-xl modal-dialog-centered">
|
<div class="modal-dialog modal-xl modal-dialog-centered">
|
||||||
<div class="modal-content bg-body-highlight p-6">
|
<div class="modal-content bg-body-highlight p-6">
|
||||||
<div class="modal-header justify-content-between border-0 p-0 mb-2">
|
<div class="modal-header justify-content-between border-0 p-0 mb-2">
|
||||||
@ -494,7 +494,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@ -1,134 +1,93 @@
|
|||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
{% load i18n static %}
|
{% load i18n static humanize %}
|
||||||
|
{% load custom_filters %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
|
|
||||||
<div class="row g-3">
|
<div class="row g-3">
|
||||||
<h2 class="mb-5">{{ _("Opportunities") }}</h2>
|
<div class="col-12">
|
||||||
<div class="d-xl-flex justify-content-between">
|
<h2 class="mb-3">{{ _("Opportunities") }}</h2>
|
||||||
<div class="mb-3">
|
</div>
|
||||||
<a class="btn btn-sm btn-phoenix-primary me-4" href="{% url 'opportunity_create' %}"><span class="fas fa-plus me-2"></span>{{ _("Add Opportunity") }}</a>
|
<div class="col-12">
|
||||||
|
<div class="d-flex flex-column flex-md-row justify-content-between align-items-md-center gap-3 mb-4">
|
||||||
|
<!-- Filter Controls -->
|
||||||
|
<div class="d-flex flex-column flex-lg-row align-items-start align-items-lg-center gap-3 w-100" id="filter-container">
|
||||||
|
<!-- Search Input - Wider and properly aligned -->
|
||||||
|
<div class="position-relative flex-grow-1" style="min-width: 300px;">
|
||||||
|
<span class="fas fa-search position-absolute top-50 translate-middle-y ms-3 text-body-tertiary"></span>
|
||||||
|
<input
|
||||||
|
class="form-control ps-6"
|
||||||
|
type="text"
|
||||||
|
placeholder="{% trans 'Search opportunities...' %}"
|
||||||
|
name="search"
|
||||||
|
hx-get="{% url 'opportunity_list' %}"
|
||||||
|
hx-trigger="keyup changed delay:500ms"
|
||||||
|
hx-target="#opportunities-grid"
|
||||||
|
hx-select="#opportunities-grid"
|
||||||
|
hx-include="#filter-container select"
|
||||||
|
hx-swap="outerHTML"
|
||||||
|
style="width: 100%;"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Filter Dropdowns - Aligned in a row -->
|
||||||
|
<div class="d-flex flex-column flex-sm-row gap-3 w-100" style="max-width: 500px;">
|
||||||
|
<!-- Stage Filter -->
|
||||||
|
<div class="flex-grow-1">
|
||||||
|
<select
|
||||||
|
class="form-select"
|
||||||
|
name="stage"
|
||||||
|
hx-get="{% url 'opportunity_list' %}"
|
||||||
|
hx-trigger="change"
|
||||||
|
hx-target="#opportunities-grid"
|
||||||
|
hx-select="#opportunities-grid"
|
||||||
|
hx-swap="outerHTML"
|
||||||
|
hx-include="#filter-container input, #filter-container select"
|
||||||
|
>
|
||||||
|
<option value="">{% trans "All Stages" %}</option>
|
||||||
|
{% for value, label in stage_choices %}
|
||||||
|
<option value="{{ value }}" {% if request.GET.stage == value %}selected{% endif %}>
|
||||||
|
{{ label }}
|
||||||
|
</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Sort Filter -->
|
||||||
|
<div class="flex-grow-1">
|
||||||
|
<select
|
||||||
|
class="form-select"
|
||||||
|
name="sort"
|
||||||
|
hx-get="{% url 'opportunity_list' %}"
|
||||||
|
hx-trigger="change"
|
||||||
|
hx-target="#opportunities-grid"
|
||||||
|
hx-select="#opportunities-grid"
|
||||||
|
hx-swap="outerHTML"
|
||||||
|
hx-include="#filter-container input, #filter-container select"
|
||||||
|
>
|
||||||
|
<option value="newest" {% if request.GET.sort == 'newest' %}selected{% endif %}>
|
||||||
|
{% trans "Newest First" %}
|
||||||
|
</option>
|
||||||
|
<option value="highest" {% if request.GET.sort == 'highest' %}selected{% endif %}>
|
||||||
|
{% trans "Highest Value" %}
|
||||||
|
</option>
|
||||||
|
<option value="closing" {% if request.GET.sort == 'closing' %}selected{% endif %}>
|
||||||
|
{% trans "Earliest Close Date" %}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
<div class="px-4 px-lg-6 ">
|
|
||||||
<div class="deals-items-container">
|
|
||||||
<div class="deals scrollbar">
|
|
||||||
<div class="deals-col me-4">
|
|
||||||
|
|
||||||
<div class="w-100 min-vh-50">
|
<div class="d-flex justify-content-end">
|
||||||
|
<a class="btn btn-phoenix-primary btn-sm" href="{% url 'opportunity_create' %}">
|
||||||
{% for opportunity in opportunities %}
|
<span class="fas fa-plus me-2"></span>{{ _("Add Opportunity") }}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div class="card mb-3">
|
|
||||||
<div class="card-body">
|
|
||||||
<h5 class="mb-2 ms-4">{{ opportunity.car.id_car_make.get_local_name }} - {{ opportunity.car.id_car_model.get_local_name }} - {{ opportunity.car.year }}</h5>
|
|
||||||
<a class="dropdown-indicator-icon position-absolute text-body-tertiary text-end"
|
|
||||||
href="#collapseWidthDeals-{{ opportunity.pk }}"
|
|
||||||
role="button"
|
|
||||||
data-bs-toggle="collapse"
|
|
||||||
aria-expanded="false"
|
|
||||||
aria-controls="collapseWidthDeals-{{ opportunity.pk }}">
|
|
||||||
<span class="fa-solid fa-angle-down text-end"></span>
|
|
||||||
</a>
|
</a>
|
||||||
<div class="d-flex align-items-center justify-content-between mb-3">
|
|
||||||
<div class="d-flex gap-3">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="d-flex">
|
|
||||||
<span class="me-2" data-feather="clock" style="stroke-width:2;"></span>
|
|
||||||
<p class="mb-0 fs-9 fw-semibold text-body-tertiary date">{{ opportunity.created|date }}<span class="text-body-quaternary"> . {{ opportunity.created|time}}</span></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="deals-items-head d-flex align-items-center mb-2">
|
|
||||||
<a class="text-primary fw-bold line-clamp-1 me-3 mb-0 fs-9" href="{% url 'opportunity_detail' opportunity.pk %}">{{ _("View") }}</a>
|
|
||||||
<p class="fs-10 mb-0 mt-1 d-none"><span class="me-1 text-body-quaternary" data-feather="grid" style="stroke-width:2; height: 12px; width: 12px"></span>{{ opportunity.get_stage_display }}</p>
|
|
||||||
<p class="ms-auto fs-9 text-body-emphasis fw-semibold mb-0 deals-revenue">{{ opportunity.car.finances.total }}</p>
|
|
||||||
</div>
|
|
||||||
<div class="deals-company-agent d-flex flex-between-center">
|
|
||||||
<div class="d-flex align-items-center"><span class="uil uil-user me-2"></span>
|
|
||||||
<p class="text-body-secondary fw-bold fs-10 mb-0">{{ opportunity.customer.get_full_name }}</p>
|
|
||||||
</div>
|
|
||||||
<div class="d-flex align-items-center"><span class="uil uil-headphones me-2"></span>
|
|
||||||
<p class="text-body-secondary fw-bold fs-10 mb-0">{{ opportunity.staff.name }}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="collapse" id="collapseWidthDeals-{{ opportunity.pk }}">
|
|
||||||
<div class="d-flex gap-2 mb-5"><span class="badge badge-phoenix fs-10 badge-phoenix-info">{{ opportunity.get_stage_display }}</span><span class="badge badge-phoenix fs-10 badge-phoenix-danger">{{ opportunity.get_status_display }}</span></div>
|
|
||||||
<table class="mb-4 w-100 table-stats table-stats">
|
|
||||||
<tr>
|
|
||||||
<th>{{ _("Details") }}</th>
|
|
||||||
<th>:</th>
|
|
||||||
<th></th>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="py-1">
|
|
||||||
<div class="d-flex align-items-center"><span class="me-2 text-body-tertiary" data-feather="dollar-sign"></span>
|
|
||||||
<p class="fw-semibold fs-9 mb-0 text-body-tertiary">{{ _("Expected Revenue")}}</p>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td class="d-none d-sm-block pe-sm-2">:</td>
|
|
||||||
<td class="py-1">
|
|
||||||
<p class="ps-6 ps-sm-0 fw-semibold fs-9 mb-0 mb-0 pb-3 pb-sm-0 text-body-emphasis">{{ opportunity.car.finances.total }}</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="py-1">
|
|
||||||
<div class="d-flex align-items-center"><span class="me-2 text-body-tertiary" data-feather="user" style="width:16px; height:16px"></span>
|
|
||||||
<p class="fw-semibold fs-9 mb-0 text-body-tertiary">{{ _("Contact") }}</p>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td class=" d-none d-sm-block pe-sm-2">:</td>
|
|
||||||
<td class="py-1">
|
|
||||||
<p class="fw-semibold fs-9 mb-0 mb-0 pb-3 pb-sm-0 text-body-emphasis d-flex align-items-center gap-2"><a href=""> <span class="fa-solid fa-square-phone text-body-tertiary"></span></a><a href=""> <span class="fa-solid fa-square-envelope text-body-tertiary"></span></a><a href=""> <span class="fab fa-whatsapp-square text-body-tertiary"></span></a></p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="py-1">
|
|
||||||
<div class="d-flex align-items-center"><span class="me-2 text-body-tertiary" data-feather="calendar" style="width:16px; height:16px"></span>
|
|
||||||
<p class="fw-semibold fs-9 mb-0 text-body-tertiary">{{ _("Closing Date")}}</p>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td class=" d-none d-sm-block pe-sm-2">:</td>
|
|
||||||
<td class="py-1">
|
|
||||||
<p class="fw-semibold fs-9 mb-0 mb-0 pb-3 pb-sm-0 text-body-emphasis">{{ opportunity.closing_date }}</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
</table>
|
|
||||||
<p class="fs-9 mb-1 fw-bold"> {{ _("Probability") }}: %</p>
|
|
||||||
<div class="progress" style="height:16px">
|
|
||||||
{% if opportunity.probability >= 25 and opportunity.probability < 49 %}
|
|
||||||
<div class="progress-bar rounded-pill bg-danger-dark" role="progressbar" style="width: {{ opportunity.probability }}%" aria-valuenow="{{ opportunity.probability }}" aria-valuemin="0" aria-valuemax="100">
|
|
||||||
<span class="fw-bolder fs-9 text-sm-end me-1">{{ opportunity.probability }}</span>
|
|
||||||
</div>
|
|
||||||
{% elif opportunity.probability >= 50 and opportunity.probability <= 74 %}
|
|
||||||
<div class="progress-bar rounded-pill bg-warning-dark" role="progressbar" style="width: {{ opportunity.probability }}%" aria-valuenow="{{ opportunity.probability }}" aria-valuemin="0" aria-valuemax="100">
|
|
||||||
<span class="fw-bolder fs-9 text-sm-end me-1">{{ opportunity.probability }}</span>
|
|
||||||
</div>
|
|
||||||
{% elif opportunity.probability >= 75 and opportunity.probability <= 100 %}
|
|
||||||
<div class="progress-bar rounded-pill bg-success-dark" role="progressbar" style="width: {{ opportunity.probability }}%" aria-valuenow="{{ opportunity.probability }}" aria-valuemin="0" aria-valuemax="100">
|
|
||||||
<span class="fw-bolder fs-9 text-sm-end me-1">{{ opportunity.probability }}</span>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% endfor %}
|
<div id="opportunities-grid" class="row g-4 px-2 px-lg-4 mt-1">
|
||||||
</div>
|
{% include 'crm/opportunities/partials/opportunity_grid.html' %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>Logs for {{ opportunity.deal_name }}</h1>
|
<h1>Logs for {{ opportunity.deal_name }}</h1>
|
||||||
<div class="table-list" id="opportunityTable">
|
<div class="table-list" id="opportunityTable">
|
||||||
</div>
|
</div>
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Action</th>
|
<th>Action</th>
|
||||||
@ -31,5 +31,5 @@
|
|||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
109
templates/crm/opportunities/partials/opportunity_grid.html
Normal file
109
templates/crm/opportunities/partials/opportunity_grid.html
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
{% load i18n static humanize %}
|
||||||
|
{% load custom_filters %}
|
||||||
|
{% block customCSS %}
|
||||||
|
<style>
|
||||||
|
.bg-success-soft {
|
||||||
|
background-color: rgba(25, 135, 84, 0.1) !important;
|
||||||
|
opacity: .8;
|
||||||
|
}
|
||||||
|
.bg-danger-soft {
|
||||||
|
background-color: rgba(220, 53, 69, 0.1) !important;
|
||||||
|
opacity: .8;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
{% endblock customCSS %}
|
||||||
|
|
||||||
|
{% for opportunity in opportunities %}
|
||||||
|
<div class="col-12 col-md-6 col-lg-4 col-xl-3">
|
||||||
|
<div class="card h-100
|
||||||
|
{% if opportunity.get_stage_display == 'Closed Won' %}bg-success-soft
|
||||||
|
{% elif opportunity.get_stage_display == 'Closed Lost' %}bg-danger-soft{% endif %}">
|
||||||
|
<div class="card-body">
|
||||||
|
<h5 class="mb-4">Opportunity for {{ opportunity.customer.customer_name }}</h5>
|
||||||
|
|
||||||
|
<div class="d-flex align-items-center justify-content-between mb-3">
|
||||||
|
<div class="d-flex gap-2">
|
||||||
|
{% if opportunity.get_stage_display == "Negotiation" %}
|
||||||
|
<span class="badge badge-phoenix fs-10 badge-phoenix-primary">{{ opportunity.get_stage_display }}</span>
|
||||||
|
{% elif opportunity.get_stage_display == "Discovery" %}
|
||||||
|
<span class="badge badge-phoenix fs-10 badge-phoenix-info">{{ opportunity.get_stage_display }}</span>
|
||||||
|
{% elif opportunity.get_stage_display == "Proposal" %}
|
||||||
|
<span class="badge badge-phoenix fs-10 badge-phoenix-warning">{{ opportunity.get_stage_display }}</span>
|
||||||
|
{% elif opportunity.get_stage_display == "Closed Won" %}
|
||||||
|
<span class="badge badge-phoenix fs-10 badge-phoenix-success">{{ opportunity.get_stage_display }}</span>
|
||||||
|
{% elif opportunity.get_stage_display == "Closed Lost" %}
|
||||||
|
<span class="badge badge-phoenix fs-10 badge-phoenix-danger">{{ opportunity.get_stage_display }}</span>
|
||||||
|
{% endif %}
|
||||||
|
<span class="badge badge-phoenix fs-10
|
||||||
|
{% if opportunity.get_stage_display == 'Won' %}badge-phoenix-success
|
||||||
|
{% elif opportunity.get_stage_display == 'Lost' %}badge-phoenix-danger{% endif %}">
|
||||||
|
{{ opportunity.get_status_display }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<i class="fa-regular fa-clock"></i>
|
||||||
|
<p class="mb-0 fs-9 fw-semibold text-body-tertiary">{{ opportunity.created|naturalday|capfirst }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="deals-company-agent d-flex justify-content-between mb-3">
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<span class="uil uil-user me-2"></span>
|
||||||
|
<p class="text-body-secondary fw-bold fs-10 mb-0">{{ opportunity.staff.name }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<table class="mb-3 w-100">
|
||||||
|
<tr>
|
||||||
|
<td class="py-1">
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<span class="me-2 text-body-tertiary"><span class="currency">{{ CURRENCY }}</span></span>
|
||||||
|
<p class="fw-semibold fs-9 mb-0 text-body-tertiary">{{ _("Expected Revenue")}}</p>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td class="text-end">
|
||||||
|
<p class="fw-semibold fs-9 mb-0 text-body-emphasis"><span class="currency">{{ CURRENCY }}</span>{{ opportunity.expected_revenue }}</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td class="py-1">
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<i class="uil uil-calendar-alt"></i>
|
||||||
|
<p class="fw-semibold fs-9 mb-0 text-body-tertiary">{{ _("Closing Date")}}</p>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td class="text-end">
|
||||||
|
<p class="fw-semibold fs-9 mb-0 text-body-emphasis">{{ opportunity.closing_date|naturalday|capfirst }}</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<p class="fs-9 mb-1 fw-bold">{{ _("Probability") }}: {{ opportunity.probability }}%</p>
|
||||||
|
<div class="progress mb-3" style="height:16px">
|
||||||
|
{% if opportunity.probability >= 25 and opportunity.probability < 49 %}
|
||||||
|
<div class="progress-bar rounded-pill bg-danger-dark" role="progressbar" style="width: {{ opportunity.probability }}%" aria-valuenow="{{ opportunity.probability }}" aria-valuemin="0" aria-valuemax="100">
|
||||||
|
<span class="fw-bolder fs-9 text-sm-end me-1">{{ opportunity.probability }}</span>
|
||||||
|
</div>
|
||||||
|
{% elif opportunity.probability >= 50 and opportunity.probability <= 74 %}
|
||||||
|
<div class="progress-bar rounded-pill bg-warning-dark" role="progressbar" style="width: {{ opportunity.probability }}%" aria-valuenow="{{ opportunity.probability }}" aria-valuemin="0" aria-valuemax="100">
|
||||||
|
<span class="fw-bolder fs-9 text-sm-end me-1">{{ opportunity.probability }}</span>
|
||||||
|
</div>
|
||||||
|
{% elif opportunity.probability >= 75 and opportunity.probability <= 100 %}
|
||||||
|
<div class="progress-bar rounded-pill bg-success-dark" role="progressbar" style="width: {{ opportunity.probability }}%" aria-valuenow="{{ opportunity.probability }}" aria-valuemin="0" aria-valuemax="100">
|
||||||
|
<span class="fw-bolder fs-9 text-sm-end me-1">{{ opportunity.probability }}</span>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="d-flex gap-2">
|
||||||
|
<a class="btn btn-sm btn-phoenix-primary" href="{% url 'opportunity_detail' opportunity.pk %}">
|
||||||
|
{{ _("View Details") }} <i class="fa-solid fa-eye ms-2"></i>
|
||||||
|
</a>
|
||||||
|
<a class="btn btn-sm btn-phoenix-success" href="{% url 'update_opportunity' opportunity.pk %}">
|
||||||
|
{{ _("Update") }} <i class="fa-solid fa-pen ms-2"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
@ -5,8 +5,8 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<link rel="stylesheet" href="{% static 'flags/sprite.css' %}">
|
<link rel="stylesheet" href="{% static 'flags/sprite.css' %}">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<div class="col-sm-6 col-md-8">
|
<div class="col-sm-6 col-md-8">
|
||||||
<div class="d-sm-flex justify-content-between">
|
<div class="d-sm-flex justify-content-between">
|
||||||
@ -36,6 +36,6 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|||||||
@ -4,9 +4,9 @@
|
|||||||
{% block title %}{{ _("View Customer") }}{% endblock title %}
|
{% block title %}{{ _("View Customer") }}{% endblock title %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% include 'modal/delete_modal.html' %}
|
{% include 'modal/delete_modal.html' %}
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="mb-9">
|
<div class="mb-9">
|
||||||
<div class="row align-items-center justify-content-between g-3 mb-4">
|
<div class="row align-items-center justify-content-between g-3 mb-4">
|
||||||
<div class="col-auto">
|
<div class="col-auto">
|
||||||
@ -142,7 +142,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% for invoice in invoices %}
|
{% for invoice in invoices %}
|
||||||
<tr class="hover-actions-trigger btn-reveal-trigger position-static">
|
<tr class="hover-actions-trigger btn-reveal-trigger position-static">
|
||||||
<td class="order align-middle white-space-nowrap ps-0">
|
<td class="order align-middle white-space-nowrap ps-0">
|
||||||
@ -170,7 +170,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@ -181,7 +181,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal fade" id="noteModal" tabindex="-1" aria-labelledby="noteModalLabel" aria-hidden="true">
|
<div class="modal fade" id="noteModal" tabindex="-1" aria-labelledby="noteModalLabel" aria-hidden="true">
|
||||||
<div class="modal-dialog modal-sm">
|
<div class="modal-dialog modal-sm">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header justify-content-between align-items-start gap-5 px-4 pt-4 pb-3 border-0">
|
<div class="modal-header justify-content-between align-items-start gap-5 px-4 pt-4 pb-3 border-0">
|
||||||
@ -195,10 +195,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
const noteModal = document.getElementById("noteModal");
|
const noteModal = document.getElementById("noteModal");
|
||||||
const modalTitle = document.getElementById("noteModalLabel");
|
const modalTitle = document.getElementById("noteModalLabel");
|
||||||
|
|
||||||
@ -220,6 +220,6 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
console.error("Error loading form:", error);
|
console.error("Error loading form:", error);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -9,7 +9,7 @@
|
|||||||
<span class="fs-10 text-body-secondary me-1">{{ _("As of")}}</span>{% now "SHORT_DATETIME_FORMAT" %}
|
<span class="fs-10 text-body-secondary me-1">{{ _("As of")}}</span>{% now "SHORT_DATETIME_FORMAT" %}
|
||||||
</span></p>
|
</span></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="row justify-content-between mb-2">
|
<div class="row justify-content-between mb-2">
|
||||||
<div class="col-6 col-md-4 col-xxl-2 text-center border-translucent border-start-xxl border-end-xxl-0 border-bottom-xxl-0 border-end border-bottom pb-4 pb-xxl-0 ">
|
<div class="col-6 col-md-4 col-xxl-2 text-center border-translucent border-start-xxl border-end-xxl-0 border-bottom-xxl-0 border-end border-bottom pb-4 pb-xxl-0 ">
|
||||||
<span class="uil fs-5 lh-1 uil-users-alt text-success"></span>
|
<span class="uil fs-5 lh-1 uil-users-alt text-success"></span>
|
||||||
<a href="{% url 'user_list' %}"><h4 class="fs-6 pt-3">{{ staff }}</h4></a>
|
<a href="{% url 'user_list' %}"><h4 class="fs-6 pt-3">{{ staff }}</h4></a>
|
||||||
@ -56,7 +56,7 @@
|
|||||||
<div class="col-4 col-xl-12 col-xxl-4 border-end border-end-xl-0 border-end-xxl py-4 ps-4 ps-sm-5 ps-xl-0 ps-xxl-5">
|
<div class="col-4 col-xl-12 col-xxl-4 border-end border-end-xl-0 border-end-xxl py-4 ps-4 ps-sm-5 ps-xl-0 ps-xxl-5">
|
||||||
<h4 class="text-body mb-4">{% trans 'inventory value'|upper %}</h4>
|
<h4 class="text-body mb-4">{% trans 'inventory value'|upper %}</h4>
|
||||||
<div class="d-md-flex flex-between-center">
|
<div class="d-md-flex flex-between-center">
|
||||||
<div class="d-md-flex align-items-center gap-2">
|
<div class="d-md-flex align-items-center gap-2">
|
||||||
<span class="fas fa-money-check-alt fs-5 text-success-light dark__text-opacity-75"></span>
|
<span class="fas fa-money-check-alt fs-5 text-success-light dark__text-opacity-75"></span>
|
||||||
<div class="d-flex d-md-block gap-2 align-items-center mt-1 mt-md-0">
|
<div class="d-flex d-md-block gap-2 align-items-center mt-1 mt-md-0">
|
||||||
<p class="fs-9 mb-0 mb-md-2 text-body-tertiary text-nowrap"></p>
|
<p class="fs-9 mb-0 mb-md-2 text-body-tertiary text-nowrap"></p>
|
||||||
@ -88,14 +88,14 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="row justify-content-between">
|
<div class="row justify-content-between">
|
||||||
<div class="col-12 col-lg-12">
|
<div class="col-12 col-lg-12">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="card mb-3">
|
<div class="card mb-3">
|
||||||
<div class="bg-holder" style="background-image:url({% static 'images/bg/38.png' %});background-position:left bottom;background-size:auto;"></div>
|
<div class="bg-holder" style="background-image:url({% static 'images/bg/38.png' %});background-position:left bottom;background-size:auto;"></div>
|
||||||
|
|
||||||
<div class="card-body d-flex justify-content-between position-relative">
|
<div class="card-body d-flex justify-content-between position-relative">
|
||||||
<div class="col-sm-7 col-md-8 col-xxl-8 mb-md-3 mb-lg-0">
|
<div class="col-sm-7 col-md-8 col-xxl-8 mb-md-3 mb-lg-0">
|
||||||
<h3 class="mb-3">{{ _("Inventory by Status")}}</h3>
|
<h3 class="mb-3">{{ _("Inventory by Status")}}</h3>
|
||||||
<div class="row g-0">
|
<div class="row g-0">
|
||||||
<div class="col-6 col-xl-4">
|
<div class="col-6 col-xl-4">
|
||||||
@ -154,9 +154,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
/* Car Chart By Make */
|
/* Car Chart By Make */
|
||||||
const { getColor, rgbaColor } = window.phoenix.utils;
|
const { getColor, rgbaColor } = window.phoenix.utils;
|
||||||
const handleTooltipPosition = ([pos, , dom, , size]) => {
|
const handleTooltipPosition = ([pos, , dom, , size]) => {
|
||||||
@ -300,6 +300,6 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
|
|
||||||
<div class="row justify-content-between">
|
<div class="row justify-content-between">
|
||||||
<div class="col-12 col-lg-6">
|
<div class="col-12 col-lg-6">
|
||||||
<div class="row g-2">
|
<div class="row g-2">
|
||||||
<h3 class="fs-4 fs-md-4 fs-xl-4 fw-black mb-4">
|
<h3 class="fs-4 fs-md-4 fs-xl-4 fw-black mb-4">
|
||||||
@ -12,7 +12,7 @@
|
|||||||
<div class="bg-holder" style="background-image:url({% static 'images/bg/38.png' %});background-position:left bottom;background-size:auto;"></div>
|
<div class="bg-holder" style="background-image:url({% static 'images/bg/38.png' %});background-position:left bottom;background-size:auto;"></div>
|
||||||
|
|
||||||
<div class="card-body d-flex justify-content-between position-relative">
|
<div class="card-body d-flex justify-content-between position-relative">
|
||||||
<div class="col-sm-7 col-md-8 col-xxl-8 mb-md-3 mb-lg-0">
|
<div class="col-sm-7 col-md-8 col-xxl-8 mb-md-3 mb-lg-0">
|
||||||
<h3 class="mb-3">{{ _("Inventory by Status")}}</h3>
|
<h3 class="mb-3">{{ _("Inventory by Status")}}</h3>
|
||||||
<div class="row g-0">
|
<div class="row g-0">
|
||||||
<div class="col-6 col-xl-4">
|
<div class="col-6 col-xl-4">
|
||||||
@ -123,7 +123,7 @@
|
|||||||
<div class="col-6 col-xl-12 col-xxl-6 border-bottom py-4 ps-4 ps-sm-5 ps-xl-0 ps-xxl-5">
|
<div class="col-6 col-xl-12 col-xxl-6 border-bottom py-4 ps-4 ps-sm-5 ps-xl-0 ps-xxl-5">
|
||||||
<h4 class="text-body mb-4">{% trans 'inventory value'|upper %}</h4>
|
<h4 class="text-body mb-4">{% trans 'inventory value'|upper %}</h4>
|
||||||
<div class="d-md-flex flex-between-center">
|
<div class="d-md-flex flex-between-center">
|
||||||
<div class="d-md-flex align-items-center gap-2 order-sm-0 order-md-1 fa-2x align-items-center">
|
<div class="d-md-flex align-items-center gap-2 order-sm-0 order-md-1 fa-2x align-items-center">
|
||||||
<i class="fas fa-money-check-alt fs-4 text-success-light dark__text-opacity-75"></i>
|
<i class="fas fa-money-check-alt fs-4 text-success-light dark__text-opacity-75"></i>
|
||||||
<div class="d-flex d-md-block gap-2 align-items-center mt-1 mt-md-0">
|
<div class="d-flex d-md-block gap-2 align-items-center mt-1 mt-md-0">
|
||||||
<p class="fs-9 mb-0 mb-md-2 text-body-tertiary text-nowrap"></p>
|
<p class="fs-9 mb-0 mb-md-2 text-body-tertiary text-nowrap"></p>
|
||||||
@ -247,9 +247,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
/* Car Chart By Make */
|
/* Car Chart By Make */
|
||||||
const getColor = (name, dom = document.documentElement) => {
|
const getColor = (name, dom = document.documentElement) => {
|
||||||
return getComputedStyle(dom).getPropertyValue(`--phoenix-${name}`).trim();
|
return getComputedStyle(dom).getPropertyValue(`--phoenix-${name}`).trim();
|
||||||
@ -400,6 +400,6 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
{% load i18n static %}
|
{% load i18n static %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="ol-auto pt-5 pb-9">
|
<div class="ol-auto pt-5 pb-9">
|
||||||
<div class="row-sm">
|
<div class="row-sm">
|
||||||
<div class="row d-flex-center">
|
<div class="row d-flex-center">
|
||||||
@ -33,8 +33,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if is_paginated %}
|
{% if is_paginated %}
|
||||||
<nav aria-label="Page navigation">
|
<nav aria-label="Page navigation">
|
||||||
<ul class="pagination mb-0">
|
<ul class="pagination mb-0">
|
||||||
{% if page_obj.has_previous %}
|
{% if page_obj.has_previous %}
|
||||||
<li class="page-item py-0">
|
<li class="page-item py-0">
|
||||||
@ -70,12 +70,12 @@
|
|||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
{% extends 'base.html' %} {% load i18n static custom_filters%} {% block content %}
|
{% extends 'base.html' %} {% load i18n static custom_filters%} {% block content %}
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="row align-items-center justify-content-between g-3 mb-4">
|
<div class="row align-items-center justify-content-between g-3 mb-4">
|
||||||
<div class="col-auto">
|
<div class="col-auto">
|
||||||
<h2 class="mb-0">{% trans 'Profile' %}</h2>
|
<h2 class="mb-0">{% trans 'Profile' %}</h2>
|
||||||
@ -172,7 +172,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
{% block title %}{{ _("Update Dealer Information") }}{% endblock title %}
|
{% block title %}{{ _("Update Dealer Information") }}{% endblock title %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row my-5">
|
<div class="row my-5">
|
||||||
<div class="col-md-8">
|
<div class="col-md-8">
|
||||||
<!-- Form Header -->
|
<!-- Form Header -->
|
||||||
|
|
||||||
@ -24,5 +24,5 @@
|
|||||||
</form>
|
</form>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -1,7 +1,7 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>{% translate 'Appointment Request Notification' %}</title>
|
<title>{% translate 'Appointment Request Notification' %}</title>
|
||||||
@ -47,9 +47,9 @@
|
|||||||
color: #999;
|
color: #999;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="email-container">
|
<div class="email-container">
|
||||||
<h1>{% translate 'New Appointment Request' %}</h1>
|
<h1>{% translate 'New Appointment Request' %}</h1>
|
||||||
<p>{% translate 'Dear Admin,' %}</p>
|
<p>{% translate 'Dear Admin,' %}</p>
|
||||||
<p>{% translate 'You have received a new appointment request. Here are the details:' %}</p>
|
<p>{% translate 'You have received a new appointment request. Here are the details:' %}</p>
|
||||||
@ -69,6 +69,6 @@
|
|||||||
<div class="footer">
|
<div class="footer">
|
||||||
<p>{% translate 'This is an automated message. Please do not reply directly to this email.' %}</p>
|
<p>{% translate 'This is an automated message. Please do not reply directly to this email.' %}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>{% translate 'Appointment Reminder' %}</title>
|
<title>{% translate 'Appointment Reminder' %}</title>
|
||||||
@ -61,9 +61,9 @@
|
|||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="email-container">
|
<div class="email-container">
|
||||||
<div class="email-header">
|
<div class="email-header">
|
||||||
<h2>{% translate 'Appointment Reminder' %}</h2>
|
<h2>{% translate 'Appointment Reminder' %}</h2>
|
||||||
</div>
|
</div>
|
||||||
@ -92,6 +92,6 @@
|
|||||||
<div class="email-footer">
|
<div class="email-footer">
|
||||||
{% translate 'This is an automated message. Please do not reply directly to this email.' %}
|
{% translate 'This is an automated message. Please do not reply directly to this email.' %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>{% trans "Appointment Reschedule Confirmation" %}</title>
|
<title>{% trans "Appointment Reschedule Confirmation" %}</title>
|
||||||
<style>
|
<style>
|
||||||
@ -33,10 +33,10 @@
|
|||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!-- email_template.html -->
|
<!-- email_template.html -->
|
||||||
<div class="email-container">
|
<div class="email-container">
|
||||||
<h2>{% trans "Appointment Reschedule" %}</h2>
|
<h2>{% trans "Appointment Reschedule" %}</h2>
|
||||||
<div class="email-content">
|
<div class="email-content">
|
||||||
{% if is_confirmation %}
|
{% if is_confirmation %}
|
||||||
@ -88,6 +88,6 @@
|
|||||||
<div class="email-footer">
|
<div class="email-footer">
|
||||||
<p>{% trans "Thank you," %}<br>{{ company }}</p>
|
<p>{% trans "Thank you," %}<br>{{ company }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
{% load static %}
|
{% load static %}
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<title></title>
|
<title></title>
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
/* CLIENT-SPECIFIC STYLES */
|
/* CLIENT-SPECIFIC STYLES */
|
||||||
@ -82,17 +82,17 @@
|
|||||||
margin: 0 !important;
|
margin: 0 !important;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body style="margin: 0 !important; padding: 0; !important background-color: #ffffff;" bgcolor="#ffffff">
|
<body style="margin: 0 !important; padding: 0; !important background-color: #ffffff;" bgcolor="#ffffff">
|
||||||
|
|
||||||
<!-- HIDDEN PRE-HEADER TEXT -->
|
<!-- HIDDEN PRE-HEADER TEXT -->
|
||||||
<div style="display: none; font-size: 1px; color: #fefefe; line-height: 1px; font-family: Open Sans, Helvetica, Arial, sans-serif; max-height: 0; max-width: 0; opacity: 0; overflow: hidden;">
|
<div style="display: none; font-size: 1px; color: #fefefe; line-height: 1px; font-family: Open Sans, Helvetica, Arial, sans-serif; max-height: 0; max-width: 0; opacity: 0; overflow: hidden;">
|
||||||
{% if pre_header %}
|
{% if pre_header %}
|
||||||
{{ pre_header }}
|
{{ pre_header }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table border="0" cellpadding="0" cellspacing="0" width="100%">
|
<table border="0" cellpadding="0" cellspacing="0" width="100%">
|
||||||
<tr>
|
<tr>
|
||||||
<td align="center" valign="top" width="100%" bgcolor="#3b4a69"
|
<td align="center" valign="top" width="100%" bgcolor="#3b4a69"
|
||||||
style="background: #3b4a69 url('{% static 'img/email_hd_bg.jpg' %}'); background-size: cover; padding: 50px 15px;"
|
style="background: #3b4a69 url('{% static 'img/email_hd_bg.jpg' %}'); background-size: cover; padding: 50px 15px;"
|
||||||
@ -284,7 +284,7 @@
|
|||||||
<![endif]-->
|
<![endif]-->
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@ -2,8 +2,8 @@
|
|||||||
<footer class="footer position-absolute fs-9">
|
<footer class="footer position-absolute fs-9">
|
||||||
<div class="row g-0 justify-content-between align-items-center h-100">
|
<div class="row g-0 justify-content-between align-items-center h-100">
|
||||||
<div class="col-12 col-sm-auto text-center">
|
<div class="col-12 col-sm-auto text-center">
|
||||||
<span class="text-body"> © 2025 {{ _("All right reserved")}}</span>
|
<span class="text-body"> © 2025 {{ _("All right reserved")}}</span>
|
||||||
<span class="fw-bold">Haikal</span> | <span class="fw-bold">هيكل</span>
|
<span class="fw-bold">Haikal</span> | <span class="fw-bold">هيكل</span>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-sm-auto text-center">
|
<div class="col-12 col-sm-auto text-center">
|
||||||
|
|||||||
@ -36,7 +36,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row my-5">
|
<div class="row my-5">
|
||||||
<div class="card rounded ">
|
<div class="card rounded ">
|
||||||
<div class="card-header ">
|
<div class="card-header ">
|
||||||
<p class="mb-0">{{ _("Group Details") }}</p>
|
<p class="mb-0">{{ _("Group Details") }}</p>
|
||||||
@ -115,5 +115,5 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -6,8 +6,8 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<div class="d-sm-flex justify-content-between">
|
<div class="d-sm-flex justify-content-between">
|
||||||
|
|
||||||
@ -41,5 +41,5 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -5,7 +5,7 @@
|
|||||||
{% block title %}{% trans "Group" %}{% endblock title %}
|
{% block title %}{% trans "Group" %}{% endblock title %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<section class="">
|
<section class="">
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-auto">
|
<div class="col-auto">
|
||||||
@ -16,7 +16,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="table-responsive scrollbar mx-n1 px-1">
|
<div class="table-responsive scrollbar mx-n1 px-1">
|
||||||
|
|
||||||
<table class="table table-hover table-responsive-sm fs-9 mb-0">
|
<table class="table table-hover table-responsive-sm fs-9 mb-0">
|
||||||
<thead>
|
<thead>
|
||||||
@ -44,14 +44,14 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex justify-content-center">
|
<div class="d-flex justify-content-center">
|
||||||
{% if is_paginated %}
|
{% if is_paginated %}
|
||||||
{% include 'partials/pagination.html' %}
|
{% include 'partials/pagination.html' %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|||||||
@ -6,8 +6,8 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<div class="d-sm-flex justify-content-between">
|
<div class="d-sm-flex justify-content-between">
|
||||||
|
|
||||||
@ -41,5 +41,5 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -4,19 +4,19 @@
|
|||||||
{% block title %}{{ _("HaikalBot") }}{% endblock title %}
|
{% block title %}{{ _("HaikalBot") }}{% endblock title %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<style>
|
<style>
|
||||||
|
|
||||||
#chatbox {
|
#chatbox {
|
||||||
border: 1px solid #ccc;
|
border: 1px solid #ccc;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
height: 200px;
|
height: 200px;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<div class="row p-2">
|
<div class="row p-2">
|
||||||
<div class="card shadow-sm rounded shadow">
|
<div class="card shadow-sm rounded shadow">
|
||||||
<div class="card-header bg-primary text-white">
|
<div class="card-header bg-primary text-white">
|
||||||
<h4 class="mb-0">{% trans 'HaikalBot' %}</h4>
|
<h4 class="mb-0">{% trans 'HaikalBot' %}</h4>
|
||||||
@ -36,7 +36,7 @@
|
|||||||
|
|
||||||
<!-- Script to send to api -->
|
<!-- Script to send to api -->
|
||||||
<script>
|
<script>
|
||||||
function getCookie(name) {
|
function getCookie(name) {
|
||||||
let cookieValue = null;
|
let cookieValue = null;
|
||||||
if (document.cookie && document.cookie !== '') {
|
if (document.cookie && document.cookie !== '') {
|
||||||
const cookies = document.cookie.split(';');
|
const cookies = document.cookie.split(';');
|
||||||
@ -49,7 +49,7 @@ function getCookie(name) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return cookieValue;
|
return cookieValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const csrfToken = getCookie('csrftoken');
|
const csrfToken = getCookie('csrftoken');
|
||||||
|
|
||||||
@ -81,9 +81,9 @@ function getCookie(name) {
|
|||||||
} else {
|
} else {
|
||||||
alert("An error occurred.");
|
alert("An error occurred.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{% load i18n static %}
|
{% load i18n static %}
|
||||||
|
|
||||||
{% if user.is_authenticated %}
|
{% if user.is_authenticated %}
|
||||||
<nav class="navbar navbar-vertical navbar-expand-lg">
|
<nav class="navbar navbar-vertical navbar-expand-lg">
|
||||||
<div class="collapse navbar-collapse" id="navbarVerticalCollapse">
|
<div class="collapse navbar-collapse" id="navbarVerticalCollapse">
|
||||||
<div class="navbar-vertical-content">
|
<div class="navbar-vertical-content">
|
||||||
<ul class="navbar-nav flex-column" id="navbarVerticalNav">
|
<ul class="navbar-nav flex-column" id="navbarVerticalNav">
|
||||||
@ -142,6 +142,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="{% url 'opportunity_list' %}">
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<span class="nav-link-icon"><span data-feather="users"></span></span><span class="nav-link-text">{% trans 'Opportunity'|capfirst %}</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if perms.django_ledger.view_customermodel %}
|
{% if perms.django_ledger.view_customermodel %}
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
@ -324,7 +331,7 @@
|
|||||||
<span class="uil uil-left-arrow-to-left fs-8"></span><span class="uil uil-arrow-from-right fs-8"></span><span class="navbar-vertical-footer-text ms-2">Collapsed View</span>
|
<span class="uil uil-left-arrow-to-left fs-8"></span><span class="uil uil-arrow-from-right fs-8"></span><span class="navbar-vertical-footer-text ms-2">Collapsed View</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<nav class="navbar navbar-top fixed-top navbar-expand" id="navbarDefault">
|
<nav class="navbar navbar-top fixed-top navbar-expand" id="navbarDefault">
|
||||||
@ -357,7 +364,7 @@
|
|||||||
<label class="mb-0 theme-control-toggle-label theme-control-toggle-dark" for="themeControlToggleSm" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-title="{{ _("Switch theme")}}" style="height:32px;width:32px;"><span class="icon" data-feather="sun"></span></label>
|
<label class="mb-0 theme-control-toggle-label theme-control-toggle-dark" for="themeControlToggleSm" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-title="{{ _("Switch theme")}}" style="height:32px;width:32px;"><span class="icon" data-feather="sun"></span></label>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item dropdown">
|
<li class="nav-item dropdown">
|
||||||
<a class="nav-link lh-1 pe-0" href="#" id="languageDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false" data-bs-auto-close="outside" aria-haspopup="true" >
|
<a class="nav-link lh-1 pe-0" href="#" id="languageDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false" data-bs-auto-close="outside" aria-haspopup="true" >
|
||||||
<span class="me-1" data-feather="globe" ></span>
|
<span class="me-1" data-feather="globe" ></span>
|
||||||
</a>
|
</a>
|
||||||
@ -457,8 +464,8 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
{% load i18n static custom_filters django_ledger %}
|
{% load i18n static custom_filters django_ledger %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% if request.user.is_authenticated %}
|
{% if request.user.is_authenticated %}
|
||||||
<div
|
<div
|
||||||
id="dashboard-content"
|
id="dashboard-content"
|
||||||
hx-get="{% if request.user.dealer %}{% url 'manager_dashboard' %}{% else %}{% url 'sales_dashboard' %}{% endif %}"
|
hx-get="{% if request.user.dealer %}{% url 'manager_dashboard' %}{% else %}{% url 'sales_dashboard' %}{% endif %}"
|
||||||
@ -14,6 +14,6 @@
|
|||||||
<p>Loading dashboard...</p>
|
<p>Loading dashboard...</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -1,7 +1,7 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row mt-4">
|
<div class="row mt-4">
|
||||||
<h5 class="text-center">{% trans "Add Colors" %}</h5>
|
<h5 class="text-center">{% trans "Add Colors" %}</h5>
|
||||||
<p class="text-center">{% trans "Select exterior and interior colors for" %} {{ car.id_car_make.get_local_name }} {{ car.id_car_model.get_local_name }}</p>
|
<p class="text-center">{% trans "Select exterior and interior colors for" %} {{ car.id_car_make.get_local_name }} {{ car.id_car_model.get_local_name }}</p>
|
||||||
|
|
||||||
@ -58,9 +58,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.color-card {
|
.color-card {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
@ -113,5 +113,5 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -2,7 +2,7 @@
|
|||||||
{% load crispy_forms_filters %}
|
{% load crispy_forms_filters %}
|
||||||
|
|
||||||
<form method="post" id="customCardForm" action="{% url 'add_custom_card' car.pk %}">
|
<form method="post" id="customCardForm" action="{% url 'add_custom_card' car.pk %}">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{{ form|crispy }}
|
{{ form|crispy }}
|
||||||
<div class="d-flex gap-1">
|
<div class="d-flex gap-1">
|
||||||
<button type="button"
|
<button type="button"
|
||||||
|
|||||||
@ -5,12 +5,12 @@
|
|||||||
{% block title %}Delete Car{% endblock %}
|
{% block title %}Delete Car{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>Delete Car</h1>
|
<h1>Delete Car</h1>
|
||||||
<p>Are you sure you want to delete the car "{{ car }}"?</p>
|
<p>Are you sure you want to delete the car "{{ car }}"?</p>
|
||||||
|
|
||||||
<form method="post">
|
<form method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<button type="submit" class="btn btn-danger">Confirm Delete</button>
|
<button type="submit" class="btn btn-danger">Confirm Delete</button>
|
||||||
<a href="{% url 'car_detail' car.pk %}" class="btn btn-secondary">{% trans 'Cancel' %}</a>
|
<a href="{% url 'car_detail' car.pk %}" class="btn btn-secondary">{% trans 'Cancel' %}</a>
|
||||||
</form>
|
</form>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -2,7 +2,7 @@
|
|||||||
{% load i18n static custom_filters %}
|
{% load i18n static custom_filters %}
|
||||||
{% block title %}{{ _("Car Details") }}{% endblock %}
|
{% block title %}{{ _("Car Details") }}{% endblock %}
|
||||||
{% block customCSS %}
|
{% block customCSS %}
|
||||||
<style>
|
<style>
|
||||||
.disabled{
|
.disabled{
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
@ -13,11 +13,11 @@
|
|||||||
left: 90%;
|
left: 90%;
|
||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
{% endblock customCSS %}
|
{% endblock customCSS %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% if not car.ready %}
|
{% if not car.ready %}
|
||||||
<div class="alert alert-outline-warning d-flex align-items-center" role="alert">
|
<div class="alert alert-outline-warning d-flex align-items-center" role="alert">
|
||||||
<i class="fa-solid fa-circle-info fs-6"></i>
|
<i class="fa-solid fa-circle-info fs-6"></i>
|
||||||
<p class="mb-0 flex-1">{{ _("This car information is not complete , please add colors and finances before making it ready for sale .") }}</p>
|
<p class="mb-0 flex-1">{{ _("This car information is not complete , please add colors and finances before making it ready for sale .") }}</p>
|
||||||
@ -43,11 +43,11 @@
|
|||||||
<i class="fa-solid fa-circle-info fs-6"></i>
|
<i class="fa-solid fa-circle-info fs-6"></i>
|
||||||
<p class="mb-0 flex-1">{{ _("This car is reserved until ") }}{{ car.get_reservation.reserved_until }}</p>
|
<p class="mb-0 flex-1">{{ _("This car is reserved until ") }}{{ car.get_reservation.reserved_until }}</p>
|
||||||
<button class="btn-close" type="button" data-bs-dismiss="alert" aria-label="Close"></button>
|
<button class="btn-close" type="button" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<!-- Main row -->
|
<!-- Main row -->
|
||||||
<div class="row-fluid {% if car.status == 'sold' %}disabled{% endif %}">
|
<div class="row-fluid {% if car.status == 'sold' %}disabled{% endif %}">
|
||||||
<div class="row g-3 justify-content-between">
|
<div class="row g-3 justify-content-between">
|
||||||
<div class="col-lg-12 col-xl-6">
|
<div class="col-lg-12 col-xl-6">
|
||||||
<div class="card rounded shadow d-flex align-content-center {% if car.get_transfer %}disabled{% endif %}">
|
<div class="card rounded shadow d-flex align-content-center {% if car.get_transfer %}disabled{% endif %}">
|
||||||
@ -411,10 +411,10 @@
|
|||||||
{% if car.status == 'sold' %}
|
{% if car.status == 'sold' %}
|
||||||
<img class="car_status" src="{% static 'images/sold.png' %}" width="200" height="100" alt="">
|
<img class="car_status" src="{% static 'images/sold.png' %}" width="200" height="100" alt="">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Custom Card Modal -->
|
<!-- Custom Card Modal -->
|
||||||
<div class="modal fade" id="customCardModal" tabindex="-1" aria-labelledby="customCardModalLabel" aria-hidden="true">
|
<div class="modal fade" id="customCardModal" tabindex="-1" aria-labelledby="customCardModalLabel" aria-hidden="true">
|
||||||
<div class="modal-dialog modal-sm">
|
<div class="modal-dialog modal-sm">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
@ -426,10 +426,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Registration Modal -->
|
<!-- Registration Modal -->
|
||||||
<div class="modal fade" id="registrationModal" tabindex="-1" aria-labelledby="registrationModalLabel" aria-hidden="true">
|
<div class="modal fade" id="registrationModal" tabindex="-1" aria-labelledby="registrationModalLabel" aria-hidden="true">
|
||||||
<div class="modal-dialog modal-sm">
|
<div class="modal-dialog modal-sm">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
@ -441,10 +441,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Reservation Modal -->
|
<!-- Reservation Modal -->
|
||||||
<div class="modal fade" id="reserveModal" tabindex="-1" aria-labelledby="reserveModalLabel" aria-hidden="true">
|
<div class="modal fade" id="reserveModal" tabindex="-1" aria-labelledby="reserveModalLabel" aria-hidden="true">
|
||||||
<div class="modal-dialog modal-sm">
|
<div class="modal-dialog modal-sm">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
@ -454,7 +454,7 @@
|
|||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
{% trans 'Are you sure you want to reserve this car?' %}
|
{% trans 'Are you sure you want to reserve this car?' %}
|
||||||
</div>
|
</div>
|
||||||
<form method="POST" action="{% url 'reserve_car' car.id %}" class="form ">
|
<form method="POST" action="{% url 'reserve_car' car.id %}" class="form ">
|
||||||
|
|
||||||
|
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
@ -476,9 +476,9 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- Specification Modal -->
|
<!-- Specification Modal -->
|
||||||
<div class="modal fade" id="specificationsModal" tabindex="-1" aria-labelledby="specificationsModalLabel" aria-hidden="true">
|
<div class="modal fade" id="specificationsModal" tabindex="-1" aria-labelledby="specificationsModalLabel" aria-hidden="true">
|
||||||
<div class="modal-dialog modal-lg modal-dialog-scrollable">
|
<div class="modal-dialog modal-lg modal-dialog-scrollable">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
@ -490,8 +490,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
|
|
||||||
|
|
||||||
@ -603,7 +603,7 @@
|
|||||||
specificationsContent.innerHTML = '<p>{% trans "Error loading specifications." %}</p>';
|
specificationsContent.innerHTML = '<p>{% trans "Error loading specifications." %}</p>';
|
||||||
console.error("Error fetching specifications:", error);
|
console.error("Error fetching specifications:", error);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
document.querySelectorAll(".reserve-btn").forEach((button) => {
|
document.querySelectorAll(".reserve-btn").forEach((button) => {
|
||||||
button.addEventListener("click", async function () {
|
button.addEventListener("click", async function () {
|
||||||
@ -641,6 +641,6 @@
|
|||||||
button.classList.add("d-none");
|
button.classList.add("d-none");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
{% extends 'base.html' %} {% load crispy_forms_filters %} {% load i18n %} {% load custom_filters %} {% block title %} {% trans 'Edit Car' %} {% endblock %} {% block content %}
|
{% extends 'base.html' %} {% load crispy_forms_filters %} {% load i18n %} {% load custom_filters %} {% block title %} {% trans 'Edit Car' %} {% endblock %} {% block content %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="card rounded shadow mt-3">
|
<div class="card rounded shadow mt-3">
|
||||||
<p class="card-header bg-primary text-white rounded-top fw-bold">{% trans 'Edit Car' %}</p>
|
<p class="card-header bg-primary text-white rounded-top fw-bold">{% trans 'Edit Car' %}</p>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
@ -15,5 +15,5 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
{% block title %}{% trans "Car Finance Details" %}{% endblock %}
|
{% block title %}{% trans "Car Finance Details" %}{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row p-4">
|
<div class="row p-4">
|
||||||
<p class="mb-4">{% trans "Finance Details for" %}
|
<p class="mb-4">{% trans "Finance Details for" %}
|
||||||
{{ car.id_car_make.get_local_name }} - {{ car.id_car_model.get_local_name }}
|
{{ car.id_car_make.get_local_name }} - {{ car.id_car_model.get_local_name }}
|
||||||
</p>
|
</p>
|
||||||
@ -26,7 +26,7 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<form method="post" class="needs-validation" novalidate>
|
<form method="post" class="needs-validation" novalidate>
|
||||||
<div class="row g-1">
|
<div class="row g-1">
|
||||||
<div class="col-lg-4 col-xl-12">
|
<div class="col-lg-4 col-xl-12">
|
||||||
|
|
||||||
@ -43,7 +43,7 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- JavaScript Section -->
|
<!-- JavaScript Section -->
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
{% extends "base.html" %} {% load i18n static custom_filters %} {% block content %}
|
{% extends "base.html" %} {% load i18n static custom_filters %} {% block content %}
|
||||||
<style>
|
<style>
|
||||||
#video {
|
#video {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 480px;
|
max-width: 480px;
|
||||||
@ -10,7 +10,7 @@
|
|||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<!-- JavaScript Section -->
|
<!-- JavaScript Section -->
|
||||||
|
|
||||||
@ -23,7 +23,7 @@
|
|||||||
<button class="btn-close" type="button" data-bs-dismiss="alert" aria-label="Close"></button>
|
<button class="btn-close" type="button" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class=" container-fluid m-0 {% if not vendor_exists %}disabled{% endif %}">
|
<div class=" container-fluid m-0 {% if not vendor_exists %}disabled{% endif %}">
|
||||||
<form method="post" id="carForm" class="form needs-validation" novalidate>
|
<form method="post" id="carForm" class="form needs-validation" novalidate>
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{% include 'partials/form_errors.html' %}
|
{% include 'partials/form_errors.html' %}
|
||||||
@ -297,9 +297,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
function getCookie(name) {
|
function getCookie(name) {
|
||||||
let cookieValue = null;
|
let cookieValue = null;
|
||||||
if (document.cookie && document.cookie !== "") {
|
if (document.cookie && document.cookie !== "") {
|
||||||
@ -606,7 +606,7 @@
|
|||||||
loadSeries(e.target.value, yearSelect.value);
|
loadSeries(e.target.value, yearSelect.value);
|
||||||
})
|
})
|
||||||
decodeVinBtn.addEventListener("click", decodeVin);
|
decodeVinBtn.addEventListener("click", decodeVin);
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
function showLoading() {
|
function showLoading() {
|
||||||
@ -630,6 +630,6 @@
|
|||||||
titleText: msg,
|
titleText: msg,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
{% extends "base.html" %} {% load i18n static custom_filters %} {% block content %}
|
{% extends "base.html" %} {% load i18n static custom_filters %} {% block content %}
|
||||||
<style>
|
<style>
|
||||||
#video {
|
#video {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 480px;
|
max-width: 480px;
|
||||||
@ -9,14 +9,14 @@
|
|||||||
.modal-dialog {
|
.modal-dialog {
|
||||||
max-width: 95%;
|
max-width: 95%;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
{% include 'partials/form_errors.html' %}
|
{% include 'partials/form_errors.html' %}
|
||||||
|
|
||||||
<!-- JavaScript Section -->
|
<!-- JavaScript Section -->
|
||||||
<script src="https://unpkg.com/@zxing/library@latest"></script>
|
<script src="https://unpkg.com/@zxing/library@latest"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/tesseract.js@5/dist/tesseract.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/tesseract.js@5/dist/tesseract.min.js"></script>
|
||||||
|
|
||||||
<div class="container-lg">
|
<div class="container-lg">
|
||||||
<form method="post" id="carForm" class="form needs-validation" novalidate>
|
<form method="post" id="carForm" class="form needs-validation" novalidate>
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<div class="d-flex flex-column min-vh-100">
|
<div class="d-flex flex-column min-vh-100">
|
||||||
@ -341,9 +341,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- CAR FORM -->
|
<!-- CAR FORM -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
function getCookie(name) {
|
function getCookie(name) {
|
||||||
let cookieValue = null;
|
let cookieValue = null;
|
||||||
if (document.cookie && document.cookie !== "") {
|
if (document.cookie && document.cookie !== "") {
|
||||||
@ -646,7 +646,7 @@
|
|||||||
loadSeries(e.target.value, yearSelect.value);
|
loadSeries(e.target.value, yearSelect.value);
|
||||||
})
|
})
|
||||||
decodeVinBtn.addEventListener("click", decodeVin);
|
decodeVinBtn.addEventListener("click", decodeVin);
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
function showLoading() {
|
function showLoading() {
|
||||||
@ -670,6 +670,6 @@
|
|||||||
titleText: msg,
|
titleText: msg,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -2,12 +2,12 @@
|
|||||||
{% load i18n static %}
|
{% load i18n static %}
|
||||||
|
|
||||||
{% block title %}
|
{% block title %}
|
||||||
{% trans "inventory"|capfirst %}
|
{% trans "inventory"|capfirst %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row g-3 justify-content-between">
|
<div class="row g-3 justify-content-between">
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<div class="card border h-100 w-100 overflow-hidden">
|
<div class="card border h-100 w-100 overflow-hidden">
|
||||||
<div class="bg-holder d-block bg-card" style="background-image:url({% static 'images/spot-illustrations/32.png' %});background-position: top right;">
|
<div class="bg-holder d-block bg-card" style="background-image:url({% static 'images/spot-illustrations/32.png' %});background-position: top right;">
|
||||||
@ -41,8 +41,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row g-3 justify-content-between mt-4">
|
<div class="row g-3 justify-content-between mt-4">
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<div class="table-list" id="inventoryTable">
|
<div class="table-list" id="inventoryTable">
|
||||||
<div class="table-responsive scrollbar mb-3">
|
<div class="table-responsive scrollbar mb-3">
|
||||||
@ -131,5 +131,5 @@
|
|||||||
{% include 'partials/pagination.html' %}
|
{% include 'partials/pagination.html' %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -3,7 +3,7 @@
|
|||||||
{% load custom_filters %}
|
{% load custom_filters %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row-fluid p-2">
|
<div class="row-fluid p-2">
|
||||||
<!-- Display Validation Errors -->
|
<!-- Display Validation Errors -->
|
||||||
{% if errors %}
|
{% if errors %}
|
||||||
<div class="alert alert-danger">
|
<div class="alert alert-danger">
|
||||||
@ -15,7 +15,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<!-- Option Modal -->
|
<!-- Option Modal -->
|
||||||
<div class="modal fade" id="optionsModal"
|
<div class="modal fade" id="optionsModal"
|
||||||
data-bs-backdrop="static"
|
data-bs-backdrop="static"
|
||||||
data-bs-keyboard="false"
|
data-bs-keyboard="false"
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
@ -32,10 +32,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Specification Modal -->
|
<!-- Specification Modal -->
|
||||||
<div class="modal fade" id="specificationsModal"
|
<div class="modal fade" id="specificationsModal"
|
||||||
data-bs-backdrop="static"
|
data-bs-backdrop="static"
|
||||||
data-bs-keyboard="false"
|
data-bs-keyboard="false"
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
@ -52,7 +52,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- CAR FORM -->
|
<!-- CAR FORM -->
|
||||||
<form method="post" id="carForm" class="form">
|
<form method="post" id="carForm" class="form">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
@ -232,13 +232,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- JavaScript Section -->
|
<!-- JavaScript Section -->
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
const vinInput = document.getElementById('vin');
|
const vinInput = document.getElementById('vin');
|
||||||
const statusSelect = document.getElementById('status');
|
const statusSelect = document.getElementById('status');
|
||||||
const stockTypeSelect = document.getElementById('stock_type');
|
const stockTypeSelect = document.getElementById('stock_type');
|
||||||
@ -593,7 +593,7 @@ checkFormCompletion();
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -15,7 +15,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-12 p-1">
|
<div class="col-md-12 p-1">
|
||||||
<div class="table-responsive scrollbar mx-n1 p-1 align-center">
|
<div class="table-responsive scrollbar mx-n1 p-1 align-center">
|
||||||
{% render_table table %}
|
{% render_table table %}
|
||||||
@ -23,8 +23,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
{% load custom_filters %}
|
{% load custom_filters %}
|
||||||
|
|
||||||
{% block customCSS %}
|
{% block customCSS %}
|
||||||
<style>
|
<style>
|
||||||
.htmx-indicator{
|
.htmx-indicator{
|
||||||
opacity:0;
|
opacity:0;
|
||||||
transition: opacity 500ms ease-in;
|
transition: opacity 500ms ease-in;
|
||||||
@ -21,7 +21,7 @@
|
|||||||
.transition {
|
.transition {
|
||||||
transition: all ease-in 1s ;
|
transition: all ease-in 1s ;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
{% endblock customCSS %}
|
{% endblock customCSS %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
@ -189,7 +189,7 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block customJS %}
|
{% block customJS %}
|
||||||
<script>
|
<script>
|
||||||
links = document.querySelectorAll('.nav-link')
|
links = document.querySelectorAll('.nav-link')
|
||||||
links.forEach(link => {
|
links.forEach(link => {
|
||||||
link.addEventListener('click', () => {
|
link.addEventListener('click', () => {
|
||||||
@ -223,5 +223,5 @@
|
|||||||
document.querySelector('.car_status').removeAttribute('disabled')
|
document.querySelector('.car_status').removeAttribute('disabled')
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
{% endblock customJS %}
|
{% endblock customJS %}
|
||||||
@ -13,5 +13,5 @@
|
|||||||
<button type="submit" class="btn btn-phoenix-success">{% trans "Save" %}</button>
|
<button type="submit" class="btn btn-phoenix-success">{% trans "Save" %}</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -13,5 +13,5 @@
|
|||||||
<button type="submit" class="btn btn-phoenix-primary">{% trans "Sell" %}</button>
|
<button type="submit" class="btn btn-phoenix-primary">{% trans "Sell" %}</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -2,7 +2,7 @@
|
|||||||
{% load static i18n %}
|
{% load static i18n %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
|
||||||
<div id="car_list" data-list="">
|
<div id="car_list" data-list="">
|
||||||
<div class="search-box mb-3 mx-auto">
|
<div class="search-box mb-3 mx-auto">
|
||||||
@ -48,10 +48,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
let currentPage = 1;
|
let currentPage = 1;
|
||||||
|
|
||||||
function loadPage(page) {
|
function loadPage(page) {
|
||||||
@ -144,7 +144,7 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
|
|
||||||
// Load the first page when the document is ready
|
// Load the first page when the document is ready
|
||||||
loadPage(currentPage);
|
loadPage(currentPage);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -1,10 +1,10 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load static %}
|
{% load static %}
|
||||||
{% load custom_filters %}
|
{% load custom_filters %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<style>
|
<style>
|
||||||
.color-option {
|
.color-option {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@ -62,18 +62,18 @@
|
|||||||
.btn-group button {
|
.btn-group button {
|
||||||
margin: 0 5px;
|
margin: 0 5px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<div class="row mt-3">
|
<div class="row mt-3">
|
||||||
<form method="post">
|
<form method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<div class="d-flex flex-column min-vh-100">
|
<div class="d-flex flex-column min-vh-100">
|
||||||
<div class="d-flex flex-column flex-sm-grow-1 ms-sm-14 p-4">
|
<div class="d-flex flex-column flex-sm-grow-1 ms-sm-14 p-4">
|
||||||
<main class="d-grid gap-4 p-1">
|
<main class="d-grid gap-4 p-1">
|
||||||
{% if car.colors.exists %}
|
{% if car.colors.exists %}
|
||||||
<p class="text-center mb-4">{% trans 'Update Color' %}</p>
|
<p class="text-center mb-4">{% trans 'Update Color' %}</p>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="form-title">
|
<div class="form-title">
|
||||||
<p>{% trans 'Add Color for' %} {{ car.id_car_make.get_local_name }} {{ car.id_car_model.get_local_name }}</p>
|
<p>{% trans 'Add Color for' %} {{ car.id_car_make.get_local_name }} {{ car.id_car_model.get_local_name }}</p>
|
||||||
</div>
|
</div>
|
||||||
<!-- Color Type Selection -->
|
<!-- Color Type Selection -->
|
||||||
@ -110,7 +110,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
function highlightSelectedColor(selectedId) {
|
function highlightSelectedColor(selectedId) {
|
||||||
document.querySelectorAll('.color-option').forEach(option => {
|
document.querySelectorAll('.color-option').forEach(option => {
|
||||||
@ -129,5 +129,5 @@
|
|||||||
document.getElementById()
|
document.getElementById()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
@ -2,15 +2,15 @@
|
|||||||
<div class="margin10 center" style="min-height:120px;">
|
<div class="margin10 center" style="min-height:120px;">
|
||||||
<div data-aaad="true" data-aa-adunit="/22815767462/CLHX_728v_1" data-status="rendered" id="9868dff0-5025-4bf8-ba3a-df1a6220e51b" data-aa-device="["bigDesktop","desktop","smallDesktop","tablet"]" data-aa-sizes="[[970,90],[728,90]]" data-aa-lazy-loaded="false" data-aa-refresh-viewable="30" data-google-query-id="CL7JkYCp64kDFZp1pAQdPh4w0w"><div id="google_ads_iframe_/22815767462,22668611618/CLHX_728v_1_0__row__" style="border: 0pt none;"><iframe id="google_ads_iframe_/22815767462,22668611618/CLHX_728v_1_0" name="google_ads_iframe_/22815767462,22668611618/CLHX_728v_1_0" title="3rd party ad content" width="1" height="1" scrolling="no" marginwidth="0" marginheight="0" frameborder="0" aria-label="Advertisement" tabindex="0" allow="private-state-token-redemption;attribution-reporting" data-load-complete="true" style="border: 0px; vertical-align: bottom; width: 728px; height: 90px;" data-google-row-id="1"></iframe></div></div>
|
<div data-aaad="true" data-aa-adunit="/22815767462/CLHX_728v_1" data-status="rendered" id="9868dff0-5025-4bf8-ba3a-df1a6220e51b" data-aa-device="["bigDesktop","desktop","smallDesktop","tablet"]" data-aa-sizes="[[970,90],[728,90]]" data-aa-lazy-loaded="false" data-aa-refresh-viewable="30" data-google-query-id="CL7JkYCp64kDFZp1pAQdPh4w0w"><div id="google_ads_iframe_/22815767462,22668611618/CLHX_728v_1_0__row__" style="border: 0pt none;"><iframe id="google_ads_iframe_/22815767462,22668611618/CLHX_728v_1_0" name="google_ads_iframe_/22815767462,22668611618/CLHX_728v_1_0" title="3rd party ad content" width="1" height="1" scrolling="no" marginwidth="0" marginheight="0" frameborder="0" aria-label="Advertisement" tabindex="0" allow="private-state-token-redemption;attribution-reporting" data-load-complete="true" style="border: 0px; vertical-align: bottom; width: 728px; height: 90px;" data-google-row-id="1"></iframe></div></div>
|
||||||
<div data-aaad="true" data-aa-adunit="/22815767462/CLHX_Mob_300v_1" data-status="skipped" id="0b22b9ef-8269-48aa-8684-e1c990efc466" data-aa-device="["mobile"]" data-aa-sizes="[[320,100],[320,50]]" data-aa-lazy-loaded="true" data-aa-refresh-viewable="30"></div>
|
<div data-aaad="true" data-aa-adunit="/22815767462/CLHX_Mob_300v_1" data-status="skipped" id="0b22b9ef-8269-48aa-8684-e1c990efc466" data-aa-device="["mobile"]" data-aa-sizes="[[320,100],[320,50]]" data-aa-lazy-loaded="true" data-aa-refresh-viewable="30"></div>
|
||||||
</div>
|
</div>
|
||||||
<h1>Popular Colors</h1>
|
<h1>Popular Colors</h1>
|
||||||
|
|
||||||
|
|
||||||
#ff80ed
|
#ff80ed
|
||||||
#065535
|
#065535
|
||||||
#000000
|
#000000
|
||||||
#133337
|
#133337
|
||||||
#ffc0cb</a><br><span class="glyphicon glyphicon-star"></span>707</div>
|
#ffc0cb</a><br><span class="glyphicon glyphicon-star"></span>707</div>
|
||||||
#ffffff</a><br><span class="glyphicon glyphicon-star"></span>607</div>
|
#ffffff</a><br><span class="glyphicon glyphicon-star"></span>607</div>
|
||||||
#ffe4e1</a><br><span class="glyphicon glyphicon-star"></span>559</div>
|
#ffe4e1</a><br><span class="glyphicon glyphicon-star"></span>559</div>
|
||||||
#008080</a><br><span class="glyphicon glyphicon-star"></span>542</div>
|
#008080</a><br><span class="glyphicon glyphicon-star"></span>542</div>
|
||||||
|
|||||||
@ -2,12 +2,12 @@
|
|||||||
{% load i18n static %}
|
{% load i18n static %}
|
||||||
|
|
||||||
{% block title %}
|
{% block title %}
|
||||||
{% trans "inventory"|capfirst %}
|
{% trans "inventory"|capfirst %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<div class="row justify-content-between">
|
<div class="row justify-content-between">
|
||||||
<div class="col-sm-12 ">
|
<div class="col-sm-12 ">
|
||||||
<div class="card border h-100 w-100 p-lg-10">
|
<div class="card border h-100 w-100 p-lg-10">
|
||||||
<div class="bg-holder bg-card" style="background-image:url({% static 'images/spot-illustrations/32.png' %});background-position: top right;">
|
<div class="bg-holder bg-card" style="background-image:url({% static 'images/spot-illustrations/32.png' %});background-position: top right;">
|
||||||
@ -22,10 +22,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- Total Cars -->
|
<!-- Total Cars -->
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<!-- Inventory by Makes -->
|
<!-- Inventory by Makes -->
|
||||||
<div class="accordion" id="makesAccordion">
|
<div class="accordion" id="makesAccordion">
|
||||||
{% for make in inventory.makes %}
|
{% for make in inventory.makes %}
|
||||||
@ -86,7 +86,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -6,11 +6,11 @@
|
|||||||
{% block title %}{% trans "Reserve Car" %}{% endblock %}
|
{% block title %}{% trans "Reserve Car" %}{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>{% trans "Reserve Car" %}</h1>
|
<h1>{% trans "Reserve Car" %}</h1>
|
||||||
|
|
||||||
<p>{% trans "You are reserving" %}: {{ car }}</p>
|
<p>{% trans "You are reserving" %}: {{ car }}</p>
|
||||||
|
|
||||||
<form method="post" class="needs-validation" novalidate>
|
<form method="post" class="needs-validation" novalidate>
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="id_reservation_start">{% trans "Reservation Start Time" %}</label>
|
<label for="id_reservation_start">{% trans "Reservation Start Time" %}</label>
|
||||||
@ -28,5 +28,5 @@
|
|||||||
</div>
|
</div>
|
||||||
<button type="submit" class="btn btn-primary">{% trans "Reserve" %}</button>
|
<button type="submit" class="btn btn-primary">{% trans "Reserve" %}</button>
|
||||||
<a href="{% url 'car_detail' car.pk %}" class="btn btn-secondary">{% trans "Cancel" %}</a>
|
<a href="{% url 'car_detail' car.pk %}" class="btn btn-secondary">{% trans "Cancel" %}</a>
|
||||||
</form>
|
</form>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -2,7 +2,7 @@
|
|||||||
{% load static i18n%}
|
{% load static i18n%}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container my-4">
|
<div class="container my-4">
|
||||||
<h3 class="mb-4">{{ _("Scan Vehicle Code")}}</h3>
|
<h3 class="mb-4">{{ _("Scan Vehicle Code")}}</h3>
|
||||||
|
|
||||||
<form id="car-form" class="mb-3">
|
<form id="car-form" class="mb-3">
|
||||||
@ -25,9 +25,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="result" class="alert mt-3" style="display:none;"></div>
|
<div id="result" class="alert mt-3" style="display:none;"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
function getCookie(name) {
|
function getCookie(name) {
|
||||||
let cookieValue = null;
|
let cookieValue = null;
|
||||||
if (document.cookie && document.cookie !== '') {
|
if (document.cookie && document.cookie !== '') {
|
||||||
@ -152,5 +152,5 @@
|
|||||||
}
|
}
|
||||||
cameraContainer.style.display = 'none';
|
cameraContainer.style.display = 'none';
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
@ -3,8 +3,8 @@
|
|||||||
|
|
||||||
{% block title %}{% trans "Transfer Car"|capfirst %}{% endblock title %}
|
{% block title %}{% trans "Transfer Car"|capfirst %}{% endblock title %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>{% trans "transfer car"|capfirst %}</h1>
|
<h1>{% trans "transfer car"|capfirst %}</h1>
|
||||||
<form method="post">
|
<form method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{% for field in form %}
|
{% for field in form %}
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@ -21,7 +21,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<button type="submit" class="btn btn-sm btn-primary">{% trans "transfer"|capfirst %}</button>
|
<button type="submit" class="btn btn-sm btn-primary">{% trans "transfer"|capfirst %}</button>
|
||||||
</form>
|
</form>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -55,7 +55,7 @@
|
|||||||
<div class="row g-3">
|
<div class="row g-3">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<h3 class="my-3">{% trans 'Transfer Details' %}</h3>
|
<h3 class="my-3">{% trans 'Transfer Details' %}</h3>
|
||||||
<div class="transfer-details">
|
<div class="transfer-details">
|
||||||
<p><strong>{% trans "Date" %} :</strong> {{transfer.created_at}}</p>
|
<p><strong>{% trans "Date" %} :</strong> {{transfer.created_at}}</p>
|
||||||
<p><strong>{% trans "From" %} :</strong> {{transfer.from_dealer}}</p>
|
<p><strong>{% trans "From" %} :</strong> {{transfer.from_dealer}}</p>
|
||||||
<p><strong>{% trans "To" %} :</strong> {{transfer.to_dealer}}</p>
|
<p><strong>{% trans "To" %} :</strong> {{transfer.to_dealer}}</p>
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{% load static i18n %}
|
{% load static i18n %}
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>transfer</title>
|
<title>transfer</title>
|
||||||
@ -121,10 +121,10 @@
|
|||||||
<link href="{% static 'css/user-rtl.min.css' %}" type="text/css" rel="stylesheet" id="user-style-rtl">
|
<link href="{% static 'css/user-rtl.min.css' %}" type="text/css" rel="stylesheet" id="user-style-rtl">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
{% if transfer.status != "approved" %}
|
{% if transfer.status != "approved" %}
|
||||||
<main class="main" id="top">
|
<main class="main" id="top">
|
||||||
<div class="px-3">
|
<div class="px-3">
|
||||||
<div class="row min-vh-100 flex-center p-5">
|
<div class="row min-vh-100 flex-center p-5">
|
||||||
<div class="col-12 col-xl-10 col-xxl-8">
|
<div class="col-12 col-xl-10 col-xxl-8">
|
||||||
@ -153,7 +153,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
</main>
|
</main>
|
||||||
{% else%}
|
{% else%}
|
||||||
<div class="button-row">
|
<div class="button-row">
|
||||||
<button id="download-pdf" class="btn btn-primary">
|
<button id="download-pdf" class="btn btn-primary">
|
||||||
<i class="fas fa-download"></i> {% trans 'Download transfer' %}
|
<i class="fas fa-download"></i> {% trans 'Download transfer' %}
|
||||||
@ -293,5 +293,5 @@
|
|||||||
$('#rejectModal').modal('hide');
|
$('#rejectModal').modal('hide');
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@ -4,7 +4,7 @@
|
|||||||
{% block title %}{{ _("Expenses") }}{% endblock title %}
|
{% block title %}{{ _("Expenses") }}{% endblock title %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row mt-4 mx-4">
|
<div class="row mt-4 mx-4">
|
||||||
<div class="d-flex justify-content-between mb-2 p-6">
|
<div class="d-flex justify-content-between mb-2 p-6">
|
||||||
<span></span>
|
<span></span>
|
||||||
<h3 class="text-center">{% trans "Expenses" %}</h3>
|
<h3 class="text-center">{% trans "Expenses" %}</h3>
|
||||||
@ -46,5 +46,5 @@
|
|||||||
<div class="d-flex justify-content-center">
|
<div class="d-flex justify-content-center">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -4,7 +4,7 @@
|
|||||||
{% block title %}{{ _("Expenses") }}{% endblock title %}
|
{% block title %}{{ _("Expenses") }}{% endblock title %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="d-flex justify-content-between">
|
<div class="d-flex justify-content-between">
|
||||||
|
|
||||||
<h3 class="mb-2">{% trans "Services" %}</h3>
|
<h3 class="mb-2">{% trans "Services" %}</h3>
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Title</title>
|
<title>Title</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@ -35,7 +35,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row my-5">
|
<div class="row my-5">
|
||||||
<div class="card rounded ">
|
<div class="card rounded ">
|
||||||
<div class="card-header bg-primary text-white ">
|
<div class="card-header bg-primary text-white ">
|
||||||
<p class="mb-0">{{ _("Bank Account Details") }}</p>
|
<p class="mb-0">{{ _("Bank Account Details") }}</p>
|
||||||
@ -69,5 +69,5 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user