Compare commits

...

7 Commits

Author SHA1 Message Date
e9d6a5da27 add ui changes to the tables in the financials 2025-05-21 19:24:14 +03:00
fe66ce1ca1 vendor ui 2025-05-21 16:32:58 +03:00
ismail
41feca462d fix slug unique issue 2025-05-20 18:39:35 +03:00
ismail
5c4ea15fdf update the note in lead and vendor disable 2025-05-20 18:17:13 +03:00
ismail
faf4eba38a fix the vendor delete and update 2025-05-20 15:01:40 +03:00
ismail
6621c1814c fix vendor delete 2025-05-20 14:35:44 +03:00
296c8a1404 Merge pull request 'check' (#38) from frontend into main
Reviewed-on: #38
2025-05-20 14:30:25 +03:00
23 changed files with 944 additions and 559 deletions

View File

@ -0,0 +1,18 @@
# Generated by Django 5.1.7 on 2025-05-20 12:00
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='vendor',
name='active',
field=models.BooleanField(default=True, verbose_name='Active'),
),
]

View File

@ -0,0 +1,19 @@
# Generated by Django 5.1.7 on 2025-05-20 12:45
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0002_vendor_active'),
]
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='inventory.customer'),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 5.1.7 on 2025-05-20 12:49
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0003_alter_opportunity_customer'),
]
operations = [
migrations.AddField(
model_name='opportunity',
name='slug',
field=models.SlugField(blank=True, help_text='Unique slug for the opportunity.', null=True, unique=True, verbose_name='Slug'),
),
]

View File

@ -0,0 +1,20 @@
# Generated by Django 5.1.7 on 2025-05-20 13:45
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0004_opportunity_slug'),
]
operations = [
migrations.AddField(
model_name='notes',
name='dealer',
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, related_name='notes', to='inventory.dealer'),
preserve_default=False,
),
]

View File

@ -188,7 +188,13 @@ class CarMake(models.Model, LocalizedNameMixin):
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
if not self.slug: if not self.slug:
self.slug = slugify(self.name) base_slug = slugify(self.name)
self.slug = base_slug
counter = 1
while self.__class__.objects.filter(slug=self.slug).exclude(pk=self.pk).exists():
self.slug = f"{base_slug}-{counter}"
counter += 1
super().save(*args, **kwargs) super().save(*args, **kwargs)
def __str__(self): def __str__(self):
return self.name return self.name
@ -204,7 +210,13 @@ class CarModel(models.Model, LocalizedNameMixin):
slug = models.SlugField(max_length=255, unique=True, blank=True, null=True) slug = models.SlugField(max_length=255, unique=True, blank=True, null=True)
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
if not self.slug: if not self.slug:
self.slug = slugify(self.name) base_slug = slugify(self.name)
self.slug = base_slug
counter = 1
while self.__class__.objects.filter(slug=self.slug).exclude(pk=self.pk).exists():
self.slug = f"{base_slug}-{counter}"
counter += 1
super().save(*args, **kwargs) super().save(*args, **kwargs)
def __str__(self): def __str__(self):
@ -227,7 +239,13 @@ class CarSerie(models.Model, LocalizedNameMixin):
slug = models.SlugField(max_length=255, unique=True, blank=True, null=True) slug = models.SlugField(max_length=255, unique=True, blank=True, null=True)
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
if not self.slug: if not self.slug:
self.slug = slugify(self.name) base_slug = slugify(self.name)
self.slug = base_slug
counter = 1
while self.__class__.objects.filter(slug=self.slug).exclude(pk=self.pk).exists():
self.slug = f"{base_slug}-{counter}"
counter += 1
super().save(*args, **kwargs) super().save(*args, **kwargs)
def __str__(self): def __str__(self):
@ -249,7 +267,13 @@ class CarTrim(models.Model, LocalizedNameMixin):
slug = models.SlugField(max_length=255, unique=True, blank=True, null=True) slug = models.SlugField(max_length=255, unique=True, blank=True, null=True)
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
if not self.slug: if not self.slug:
self.slug = slugify(self.name) base_slug = slugify(self.name)
self.slug = base_slug
counter = 1
while self.__class__.objects.filter(slug=self.slug).exclude(pk=self.pk).exists():
self.slug = f"{base_slug}-{counter}"
counter += 1
super().save(*args, **kwargs) super().save(*args, **kwargs)
def __str__(self): def __str__(self):
@ -288,7 +312,13 @@ class CarSpecification(models.Model, LocalizedNameMixin):
slug = models.SlugField(max_length=255, unique=True, blank=True, null=True) slug = models.SlugField(max_length=255, unique=True, blank=True, null=True)
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
if not self.slug: if not self.slug:
self.slug = slugify(self.name) base_slug = slugify(self.name)
self.slug = base_slug
counter = 1
while self.__class__.objects.filter(slug=self.slug).exclude(pk=self.pk).exists():
self.slug = f"{base_slug}-{counter}"
counter += 1
super().save(*args, **kwargs) super().save(*args, **kwargs)
def __str__(self): def __str__(self):
@ -324,7 +354,13 @@ class CarOption(models.Model, LocalizedNameMixin):
slug = models.SlugField(max_length=255, unique=True, blank=True, null=True) slug = models.SlugField(max_length=255, unique=True, blank=True, null=True)
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
if not self.slug: if not self.slug:
self.slug = slugify(self.name) base_slug = slugify(self.name)
self.slug = base_slug
counter = 1
while self.__class__.objects.filter(slug=self.slug).exclude(pk=self.pk).exists():
self.slug = f"{base_slug}-{counter}"
counter += 1
super().save(*args, **kwargs) super().save(*args, **kwargs)
def __str__(self): def __str__(self):
@ -1139,7 +1175,13 @@ class Customer(models.Model):
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
if not self.slug: if not self.slug:
self.slug = slugify(f"{self.first_name} {self.last_name}") base_slug = slugify(f"{self.last_name} {self.first_name}")
self.slug = base_slug
counter = 1
while self.__class__.objects.filter(slug=self.slug).exclude(pk=self.pk).exists():
self.slug = f"{base_slug}-{counter}"
counter += 1
super().save(*args, **kwargs) super().save(*args, **kwargs)
class Meta: class Meta:
@ -1447,7 +1489,8 @@ class Lead(models.Model):
def full_name(self): def full_name(self):
return f"{self.first_name} {self.last_name}" return f"{self.first_name} {self.last_name}"
def convert_to_customer(self): def convert_to_customer(self):
self.status = Status.QUALIFIED self.status = Status.NEGOTIATION
self.is_converted = True
self.save() self.save()
return self.get_customer_model() return self.get_customer_model()
def get_status(self): def get_status(self):
@ -1507,8 +1550,14 @@ class Lead(models.Model):
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
self.status = self.get_status() self.status = self.get_status()
if not self.slug: if not self.slug:
self.slug = slugify(f"{self.first_name} {self.last_name}") base_slug = slugify(f"{self.last_name} {self.first_name}")
super(Lead, self).save(*args, **kwargs) self.slug = base_slug
counter = 1
while self.__class__.objects.filter(slug=self.slug).exclude(pk=self.pk).exists():
self.slug = f"{base_slug}-{counter}"
counter += 1
super().save(*args, **kwargs)
class Schedule(models.Model): class Schedule(models.Model):
PURPOSE_CHOICES = [ PURPOSE_CHOICES = [
@ -1587,7 +1636,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",null=True,blank=True Customer, 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")
@ -1611,15 +1660,22 @@ class Opportunity(models.Model):
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"))
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)
slug = models.SlugField(null=True, blank=True, unique=True,verbose_name=_("Slug"),
help_text=_("Unique slug for the opportunity."))
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(f"opportunity {self.customer.first_name} {self.customer.last_name}")
super(Opportunity, self).save(*args, **kwargs)
class Meta: class Meta:
verbose_name = _("Opportunity") verbose_name = _("Opportunity")
verbose_name_plural = _("Opportunities") verbose_name_plural = _("Opportunities")
def __str__(self): def __str__(self):
return f"Opportunity for {self.customer.customer_name}" return f"Opportunity for {self.customer.first_name} {self.customer.last_name}"
class Notes(models.Model): class Notes(models.Model):
dealer = models.ForeignKey(Dealer, on_delete=models.CASCADE, related_name="notes")
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()
content_object = GenericForeignKey("content_type", "object_id") content_object = GenericForeignKey("content_type", "object_id")
@ -1755,12 +1811,19 @@ class Vendor(models.Model, LocalizedNameMixin):
logo = models.ImageField( logo = models.ImageField(
upload_to="logos/vendors", blank=True, null=True, verbose_name=_("Logo") upload_to="logos/vendors", blank=True, null=True, verbose_name=_("Logo")
) )
active = models.BooleanField(default=True, verbose_name=_("Active"))
created_at = models.DateTimeField(auto_now_add=True, verbose_name=_("Created At")) created_at = models.DateTimeField(auto_now_add=True, verbose_name=_("Created At"))
slug = models.SlugField(max_length=255, unique=True, verbose_name=_("Slug"), null=True,blank=True) slug = models.SlugField(max_length=255, unique=True, verbose_name=_("Slug"), null=True,blank=True)
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
if not self.slug: if not self.slug:
self.slug = slugify(self.name) base_slug = slugify(self.name)
self.slug = base_slug
counter = 1
while self.__class__.objects.filter(slug=self.slug).exclude(pk=self.pk).exists():
self.slug = f"{base_slug}-{counter}"
counter += 1
super().save(*args, **kwargs) super().save(*args, **kwargs)
class Meta: class Meta:
verbose_name = _("Vendor") verbose_name = _("Vendor")

View File

@ -83,6 +83,11 @@ urlpatterns = [
views.CustomerDetailView.as_view(), views.CustomerDetailView.as_view(),
name="customer_detail", name="customer_detail",
), ),
path(
"customers/<slug:slug>/add-note/",
views.add_note_to_customer,
name="add_note_to_customer",
),
path( path(
"customers/<slug:slug>/update/", "customers/<slug:slug>/update/",
views.CustomerUpdateView.as_view(), views.CustomerUpdateView.as_view(),
@ -94,11 +99,6 @@ urlpatterns = [
views.OpportunityCreateView.as_view(), views.OpportunityCreateView.as_view(),
name="create_opportunity", name="create_opportunity",
), ),
path(
"customers/<slug:slug>/add-note/",
views.add_note_to_customer,
name="add_note_to_customer",
),
path("crm/leads/create/", views.lead_create, name="lead_create"), path("crm/leads/create/", views.lead_create, name="lead_create"),
path( path(
"crm/leads/<slug:slug>/view/", views.LeadDetailView.as_view(), name="lead_detail" "crm/leads/<slug:slug>/view/", views.LeadDetailView.as_view(), name="lead_detail"
@ -109,13 +109,21 @@ urlpatterns = [
path("crm/leads/", views.LeadListView.as_view(), name="lead_list"), path("crm/leads/", views.LeadListView.as_view(), name="lead_list"),
path( path(
"crm/leads/<int:pk>/update/", views.LeadUpdateView.as_view(), name="lead_update" "crm/leads/<slug:slug>/update/", views.LeadUpdateView.as_view(), name="lead_update"
), ),
path("crm/leads/<slug:slug>/delete/", views.LeadDeleteView, name="lead_delete"), path("crm/leads/<slug:slug>/delete/", views.LeadDeleteView, name="lead_delete"),
path("crm/leads/<int:pk>/lead-convert/", views.lead_convert, name="lead_convert"), path("crm/leads/<slug:slug>/lead-convert/", views.lead_convert, name="lead_convert"),
path("crm/leads/<int:pk>/add-note/", views.add_note_to_lead, name="add_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(
"crm/<int:pk>/update-note/",
views.update_note,
name="update_note",
),
path(
"crm/<str:content_type>/<slug:slug>/add-note/",
views.add_note,
name="add_note",
),
path( path(
"crm/<int:pk>/update-task/", "crm/<int:pk>/update-task/",
views.update_task, views.update_task,
@ -152,13 +160,12 @@ urlpatterns = [
name="schedule_cancel", name="schedule_cancel",
), ),
path( path(
"crm/leads/<int:pk>/transfer/", "crm/leads/<slug:slug>/transfer/",
views.lead_transfer, views.lead_transfer,
name="lead_transfer", name="lead_transfer",
), ),
path( path(
"crm/opportunities/<int:pk>/add_note/", "crm/opportunities/<slug:slug>/add_note/",
views.add_note_to_opportunity, views.add_note_to_opportunity,
name="add_note_to_opportunity", name="add_note_to_opportunity",
), ),
@ -168,17 +175,22 @@ urlpatterns = [
name="opportunity_create", name="opportunity_create",
), ),
path( path(
"crm/opportunities/<int:pk>/create/", "crm/opportunities/<slug:slug>/create/",
views.OpportunityCreateView.as_view(),
name="lead_opportunity_create",
),
path(
"crm/opportunities/<slug:slug>/create/",
views.OpportunityCreateView.as_view(), views.OpportunityCreateView.as_view(),
name="opportunity_create", name="opportunity_create",
), ),
path( path(
"crm/opportunities/<int:pk>/", "crm/opportunities/<slug:slug>/",
views.OpportunityDetailView.as_view(), views.OpportunityDetailView.as_view(),
name="opportunity_detail", name="opportunity_detail",
), ),
path( path(
"crm/opportunities/<int:pk>/edit/", "crm/opportunities/<slug:slug>/edit/",
views.OpportunityUpdateView.as_view(), views.OpportunityUpdateView.as_view(),
name="update_opportunity", name="update_opportunity",
), ),
@ -193,7 +205,7 @@ urlpatterns = [
name="delete_opportunity", name="delete_opportunity",
), ),
path( path(
"crm/opportunities/<int:pk>/opportunity_update_status/", "crm/opportunities/<slug:slug>/opportunity_update_status/",
views.opportunity_update_status, views.opportunity_update_status,
name="opportunity_update_status", name="opportunity_update_status",
), ),

View File

@ -22,7 +22,7 @@ from django.http.response import StreamingHttpResponse
# Django # Django
from django.db.models import Q from django.db.models import Q
from django.conf import settings from django.conf import settings
from django.db import transaction from django.db import IntegrityError, 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 Http404, JsonResponse, HttpResponseForbidden from django.http import Http404, JsonResponse, HttpResponseForbidden
@ -1953,7 +1953,7 @@ class CustomerDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView
@login_required @login_required
def add_note_to_customer(request, pk): def add_note_to_customer(request, slug):
""" """
This function allows authenticated users to add a note to a specific customer. The This function allows authenticated users to add a note to a specific customer. The
note creation is handled by a form, which is validated after submission. If the form note creation is handled by a form, which is validated after submission. If the form
@ -1970,7 +1970,7 @@ def add_note_to_customer(request, pk):
POST request, it renders the note form template with context including POST request, it renders the note form template with context including
the form and customer. the form and customer.
""" """
customer = get_object_or_404(models.Customer, pk=pk) customer = get_object_or_404(models.Customer, slug=slug)
if request.method == "POST": if request.method == "POST":
form = forms.NoteForm(request.POST) form = forms.NoteForm(request.POST)
if form.is_valid(): if form.is_valid():
@ -1979,7 +1979,7 @@ def add_note_to_customer(request, pk):
note.created_by = request.user note.created_by = request.user
note.save() note.save()
return redirect("customer_detail", pk=customer.pk) return redirect("customer_detail", slug=customer.slug)
else: else:
form = forms.NoteForm() form = forms.NoteForm()
return render( return render(
@ -2144,13 +2144,14 @@ class VendorListView(LoginRequiredMixin, ListView):
context_object_name = "vendors" context_object_name = "vendors"
paginate_by = 10 paginate_by = 10
template_name = "vendors/vendors_list.html" template_name = "vendors/vendors_list.html"
# ordering = ["-created"]
# def get_queryset(self): def get_queryset(self):
# query = self.request.GET.get("q") query = self.request.GET.get("q")
# dealer = get_user_type(self.request) dealer = get_user_type(self.request)
# vendors = dealer.entity.get_vendors().filter(active=True) vendors = super().get_queryset().filter(dealer=dealer,active=True)
# return apply_search_filters(vendors, query) if query:
return apply_search_filters(vendors, query)
return vendors
@login_required @login_required
@ -2205,9 +2206,16 @@ class VendorCreateView(
success_message = _("Vendor created successfully") success_message = _("Vendor created successfully")
def form_valid(self, form): def form_valid(self, form):
if vendor:= models.Vendor.objects.filter(email=form.instance.email).first():
if not vendor.active:
messages.error(self.request, _("Vendor Account with this email is Deactivated,Please Contact Admin"))
else:
messages.error(self.request, _("Vendor with this email already exists"))
return redirect("vendor_create")
dealer = get_user_type(self.request) dealer = get_user_type(self.request)
form.instance.dealer = dealer form.instance.dealer = dealer
form.instance.save() form.instance.save()
return super().form_valid(form) return super().form_valid(form)
@ -4596,6 +4604,7 @@ class LeadDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
context["transfer_form"] = forms.LeadTransferForm() context["transfer_form"] = forms.LeadTransferForm()
context["activity_form"] = forms.ActivityForm() context["activity_form"] = forms.ActivityForm()
context["staff_task_form"] = forms.StaffTaskForm() context["staff_task_form"] = forms.StaffTaskForm()
context["note_form"] = forms.NoteForm()
return context return context
@ -4797,7 +4806,7 @@ def LeadDeleteView(request, slug):
@login_required @login_required
def add_note_to_lead(request, pk): def add_note_to_lead(request, slug):
""" """
Adds a note to a specific lead. This view is accessible only to authenticated Adds a note to a specific lead. This view is accessible only to authenticated
users. The function handles the POST request to create a new note associated users. The function handles the POST request to create a new note associated
@ -4813,7 +4822,7 @@ def add_note_to_lead(request, pk):
note creation or renders the note form template for GET or invalid POST requests. note creation or renders the note form template for GET or invalid POST requests.
:rtype: HttpResponse :rtype: HttpResponse
""" """
lead = get_object_or_404(models.Lead, pk=pk) lead = get_object_or_404(models.Lead, slug=slug)
if request.method == "POST": if request.method == "POST":
form = forms.NoteForm(request.POST) form = forms.NoteForm(request.POST)
if form.is_valid(): if form.is_valid():
@ -4829,7 +4838,7 @@ def add_note_to_lead(request, pk):
@login_required @login_required
def add_note_to_opportunity(request, pk): def add_note_to_opportunity(request, slug):
""" """
Add a note to a specific opportunity identified by its primary key. Add a note to a specific opportunity identified by its primary key.
@ -4843,7 +4852,7 @@ def add_note_to_opportunity(request, pk):
:type pk: int :type pk: int
:return: A redirect response to the detailed view of the opportunity. :return: A redirect response to the detailed view of the opportunity.
""" """
opportunity = get_object_or_404(models.Opportunity, pk=pk) opportunity = get_object_or_404(models.Opportunity, slug=slug)
if request.method == "POST": if request.method == "POST":
notes = request.POST.get("notes") notes = request.POST.get("notes")
if not notes: if not notes:
@ -4851,7 +4860,7 @@ def add_note_to_opportunity(request, pk):
else: else:
models.Notes.objects.create(content_object=opportunity, created_by=request.user,note=notes) models.Notes.objects.create(content_object=opportunity, created_by=request.user,note=notes)
messages.success(request, _("Note added successfully")) messages.success(request, _("Note added successfully"))
return redirect("opportunity_detail", pk=opportunity.pk) return redirect("opportunity_detail", slug=opportunity.slug)
@login_required @login_required
@ -4909,14 +4918,15 @@ def delete_note(request, pk):
""" """
note = get_object_or_404(models.Notes, pk=pk, created_by=request.user) note = get_object_or_404(models.Notes, pk=pk, created_by=request.user)
lead_pk = note.content_object.pk lead_pk = note.content_object.pk
lead = models.Lead.objects.get(pk=lead_pk)
note.delete() note.delete()
messages.success(request, _("Note deleted successfully.")) messages.success(request, _("Note deleted successfully."))
return redirect("lead_detail", pk=lead_pk) return redirect("lead_detail", slug=lead.slug)
@login_required @login_required
@permission_required("inventory.change_lead", raise_exception=True) @permission_required("inventory.change_lead", raise_exception=True)
def lead_convert(request, pk): def lead_convert(request, slug):
""" """
Converts a lead into a customer and creates a corresponding opportunity. Converts a lead into a customer and creates a corresponding opportunity.
@ -4933,20 +4943,20 @@ def lead_convert(request, pk):
:return: An HTTP response redirecting to the lead list view. :return: An HTTP response redirecting to the lead list view.
:rtype: HttpResponse :rtype: HttpResponse
""" """
lead = get_object_or_404(models.Lead, pk=pk) lead = get_object_or_404(models.Lead, slug=slug)
dealer = get_user_type(request) dealer = get_user_type(request)
if hasattr(lead, "opportunity"): if hasattr(lead, "opportunity"):
messages.error(request, _("Lead is already converted to customer")) messages.error(request, _("Lead is already converted to customer"))
else: else:
customer = lead.convert_to_customer() customer = lead.convert_to_customer()
models.Opportunity.objects.create(dealer=dealer,customer=customer,lead=lead,probability=50,stage=models.Stage.PROSPECT,staff=lead.staff,status=models.Status.QUALIFIED) models.Opportunity.objects.create(dealer=dealer,customer=customer,lead=lead,probability=50,stage=models.Stage.NEGOTIATION,staff=lead.staff)
messages.success(request, _("Lead converted to customer successfully")) messages.success(request, _("Lead converted to customer successfully"))
return redirect("lead_list") return redirect("lead_list")
@login_required @login_required
@permission_required("inventory.add_lead", raise_exception=True) @permission_required("inventory.add_lead", raise_exception=True)
def schedule_lead(request, pk): def schedule_lead(request, slug):
""" """
Handles the scheduling of a lead for an appointment. Handles the scheduling of a lead for an appointment.
@ -4969,7 +4979,7 @@ def schedule_lead(request, pk):
messages.error(request, _("You do not have permission to schedule lead")) messages.error(request, _("You do not have permission to schedule lead"))
return redirect("lead_list") return redirect("lead_list")
dealer = get_user_type(request) dealer = get_user_type(request)
lead = get_object_or_404(models.Lead, pk=pk, dealer=dealer) lead = get_object_or_404(models.Lead, slug=slug, dealer=dealer)
if request.method == "POST": if request.method == "POST":
form = forms.ScheduleForm(request.POST) form = forms.ScheduleForm(request.POST)
if form.is_valid(): if form.is_valid():
@ -4997,7 +5007,7 @@ def schedule_lead(request, pk):
) )
except ValidationError as e: except ValidationError as e:
messages.error(request, str(e)) messages.error(request, str(e))
return redirect("schedule_lead", pk=lead.pk) return redirect("schedule_lead", slug=lead.slug)
client = get_object_or_404(User, email=lead.email) client = get_object_or_404(User, email=lead.email)
# Create Appointment # Create Appointment
@ -5021,7 +5031,7 @@ def schedule_lead(request, pk):
@login_required @login_required
@permission_required("inventory.change_lead", raise_exception=True) @permission_required("inventory.change_lead", raise_exception=True)
def lead_transfer(request, pk): def lead_transfer(request, slug):
""" """
Handles the transfer of a lead to a different staff member. This view is accessible Handles the transfer of a lead to a different staff member. This view is accessible
only to authenticated users with the 'inventory.change_lead' permission. If the only to authenticated users with the 'inventory.change_lead' permission. If the
@ -5033,7 +5043,7 @@ def lead_transfer(request, pk):
:param pk: The primary key of the lead to be transferred. :param pk: The primary key of the lead to be transferred.
:return: An HTTP redirect response to the lead list view. :return: An HTTP redirect response to the lead list view.
""" """
lead = get_object_or_404(models.Lead, pk=pk) lead = get_object_or_404(models.Lead, slug=slug)
if request.method == "POST": if request.method == "POST":
form = forms.LeadTransferForm(request.POST) form = forms.LeadTransferForm(request.POST)
if form.is_valid(): if form.is_valid():
@ -5193,24 +5203,14 @@ class OpportunityCreateView(CreateView,SuccessMessageMixin, LoginRequiredMixin):
template_name = "crm/opportunities/opportunity_form.html" template_name = "crm/opportunities/opportunity_form.html"
success_message = "Opportunity created successfully." success_message = "Opportunity created successfully."
def get_context_data(self, **kwargs): def get_initial(self):
context = super().get_context_data(**kwargs) initial = super().get_initial()
dealer = get_user_type(self.request) dealer = get_user_type(self.request)
return context if self.kwargs.get("slug", None):
lead = models.Lead.objects.get(slug=self.kwargs.get("slug"),dealer=dealer)
# def get_form_kwargs(self): initial["lead"] = lead
# kwargs = super().get_form_kwargs() initial['stage'] = models.Stage.PROPOSAL
# dealer = get_user_type(self.request) return initial
# kwargs["car"].queryset = models.Car.objects.filter(dealer=dealer,)
# return kwargs
# def get_initial(self):
# initial = super().get_initial()
# if self.kwargs.get("pk", None):
# lead = models.Lead.objects.get(pk=self.kwargs.get("pk"))
# initial["customer"] = lead.customer
# return initial
def form_valid(self, form): def form_valid(self, form):
dealer = get_user_type(self.request) dealer = get_user_type(self.request)
@ -5251,7 +5251,7 @@ class OpportunityUpdateView(LoginRequiredMixin,SuccessMessageMixin, UpdateView):
success_message = "Opportunity updated successfully." 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={"slug": self.object.slug})
class OpportunityDetailView(LoginRequiredMixin, DetailView): class OpportunityDetailView(LoginRequiredMixin, DetailView):
@ -5359,7 +5359,7 @@ def delete_opportunity(request, pk):
@login_required @login_required
def opportunity_update_status(request, pk): def opportunity_update_status(request, slug):
""" """
Update the status and/or stage of a specific Opportunity instance. This is a Update the status and/or stage of a specific Opportunity instance. This is a
view function, which is generally tied to a URL endpoint in a Django application. view function, which is generally tied to a URL endpoint in a Django application.
@ -5384,7 +5384,7 @@ def opportunity_update_status(request, pk):
frontend behavior. frontend behavior.
:rtype: HttpResponse :rtype: HttpResponse
""" """
opportunity = get_object_or_404(models.Opportunity, pk=pk) opportunity = get_object_or_404(models.Opportunity, slug=slug)
status = request.GET.get("status") status = request.GET.get("status")
stage = request.GET.get("stage") stage = request.GET.get("stage")
if status: if status:
@ -5393,7 +5393,7 @@ def opportunity_update_status(request, pk):
opportunity.stage = stage opportunity.stage = stage
opportunity.save() opportunity.save()
messages.success(request,_("Opportunity status updated successfully")) messages.success(request,_("Opportunity status updated successfully"))
response = HttpResponse(redirect("opportunity_detail",pk=opportunity.pk)) response = HttpResponse(redirect("opportunity_detail",slug=opportunity.slug))
response['HX-Refresh'] = 'true' response['HX-Refresh'] = 'true'
return response return response
@ -7783,6 +7783,7 @@ def add_activity(request,content_type,slug):
else: else:
messages.error(request, _("Activity form is not valid")) messages.error(request, _("Activity form is not valid"))
return redirect(f"{content_type}_detail", slug=slug) return redirect(f"{content_type}_detail", slug=slug)
def add_task(request,content_type,slug): def add_task(request,content_type,slug):
try: try:
model = apps.get_model(f'inventory.{content_type}') model = apps.get_model(f'inventory.{content_type}')
@ -7823,4 +7824,43 @@ def update_task(request,pk):
tasks = models.Tasks.objects.filter( tasks = models.Tasks.objects.filter(
content_type__model="lead", object_id=lead.id content_type__model="lead", object_id=lead.id
) )
return render(request,'crm/leads/lead_detail.html',{'lead':lead,'tasks':tasks}) return render(request,'crm/leads/lead_detail.html',{'lead':lead,'tasks':tasks})
def add_note(request,content_type,slug):
try:
model = apps.get_model(f'inventory.{content_type}')
except LookupError:
raise Http404("Model not found")
obj = get_object_or_404(model, slug=slug)
dealer = get_user_type(request)
if request.method == "POST":
form = forms.NoteForm(request.POST)
if form.is_valid():
note = form.save(commit=False)
note.dealer = dealer
note.content_object = obj
note.created_by = request.user
note.save()
messages.success(request, _("Note added successfully"))
else:
print(form.errors)
messages.error(request, _("Note form is not valid"))
return redirect(f"{content_type}_detail", slug=slug)
def update_note(request,pk):
note = get_object_or_404(models.Notes, pk=pk)
lead = get_object_or_404(models.Lead, pk=note.content_object.id)
dealer = get_user_type(request)
if request.method == "POST":
note.note = request.POST.get('note')
note.save()
messages.success(request, _("Note updated successfully"))
return redirect(f"lead_detail", slug=lead.slug)
else:
messages.error(request, _("Note form is not valid"))
notes = models.Notes.objects.filter(
content_type__model="lead", object_id=lead.id,dealer=dealer
)
return render(request,'crm/leads/lead_detail.html',{'lead':lead,'notes':notes})

View File

@ -230,7 +230,7 @@
<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">
<form class="modal-content" action="{% url 'lead_transfer' lead.pk %}" method="post"> <form class="modal-content" action="{% url 'lead_transfer' lead.slug %}" method="post">
{% csrf_token %} {% csrf_token %}
<div class="modal-header"> <div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Reassign Lead To Another Employee</h5> <h5 class="modal-title" id="exampleModalLabel">Reassign Lead To Another Employee</h5>
@ -301,10 +301,7 @@
<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 d-flex align-items-center justify-content-between"> <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>
<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>"> <button class="btn btn-phoenix-primary btn-sm" type="button" onclick="reset_form()" data-bs-toggle="modal" data-bs-target="#noteModal"><span class="fas fa-plus me-1"></span>{{ _("Add Note") }}</button>
<span class="fas fa-plus me-1"></span>
{% trans 'Add Note' %}
</a>
</div> </div>
<div class="border-top border-bottom border-translucent" id="leadDetailsTable"> <div class="border-top border-bottom border-translucent" id="leadDetailsTable">
@ -331,9 +328,18 @@
<td class="align-middle text-body-tertiary text-start white-space-nowrap">{{ note.created|naturalday|capfirst }}</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"
<i class="fas fa-pen"></i> href="#"
</a> onclick="updateNote(this)"
class="btn btn-sm btn-phoenix-primary me-2"
data-pk="{{ note.pk }}"
data-note="{{ note.note|escapejs }}"
data-url="{% url 'update_note' 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>">
{{ _("Update") }}
</a>
<button class="btn btn-phoenix-danger btn-sm delete-btn" <button class="btn btn-phoenix-danger btn-sm delete-btn"
data-url="{% url 'delete_note_to_lead' note.pk %}" data-url="{% url 'delete_note_to_lead' note.pk %}"
data-message="Are you sure you want to delete this note?" data-message="Are you sure you want to delete this note?"
@ -535,7 +541,7 @@
</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"> {% comment %} <div class="modal fade" id="noteModal" tabindex="-1" aria-labelledby="noteModalLabel" aria-hidden="true">
<div class="modal-dialog modal-md"> <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">
@ -549,7 +555,7 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div> {% endcomment %}
<!-- activity Modal --> <!-- activity Modal -->
{% include "components/activity_modal.html" with content_type="lead" slug=lead.slug %} {% include "components/activity_modal.html" with content_type="lead" slug=lead.slug %}
@ -559,7 +565,7 @@
<div class="modal-dialog modal-md"> <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 'Task' %}</h4> <h4 class="modal-title" id="taskModalLabel">{% trans 'Task' %}</h4>
<button class="btn p-0 text-body-quaternary fs-6" data-bs-dismiss="modal" aria-label="Close"> <button class="btn p-0 text-body-quaternary fs-6" data-bs-dismiss="modal" aria-label="Close">
<span class="fas fa-times"></span> <span class="fas fa-times"></span>
</button> </button>
@ -574,34 +580,44 @@
</div> </div>
</div> </div>
</div> </div>
<!-- note Modal -->
<div class="modal fade" id="noteModal" tabindex="-1" aria-labelledby="noteModalLabel" 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 'Note' %}</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_note' 'lead' lead.slug %}" method="post" class="add_note_form">
{% csrf_token %}
{{ note_form|crispy }}
<button type="submit" class="btn btn-success w-100">{% trans 'Save' %}</button>
</form>
</div>
</div>
</div>
</div>
{% endblock content %} {% endblock content %}
{% block customJS %} {% block customJS %}
<script> <script>
function updateNote(e) {
let url = e.getAttribute('data-url')
let note = e.getAttribute('data-note')
document.querySelector('#id_note').value = note
let form = document.querySelector('.add_note_form')
form.action = url
}
function reset_form() {
document.querySelector('#id_note').value = ""
let form = document.querySelector('.add_note_form')
form.action = "{% url 'add_note' 'lead' lead.slug %}"
}
document.addEventListener("DOMContentLoaded", function () { document.addEventListener("DOMContentLoaded", function () {
const noteModal = document.getElementById("noteModal");
const modalTitle = document.getElementById("noteModalLabel");
const modalBody = noteModal.querySelector(".modal-body");
noteModal.addEventListener("show.bs.modal", function (event) {
const button = event.relatedTarget;
const url = button.getAttribute("data-url");
const title = button.getAttribute("data-note-title");
fetch(url)
.then((response) => response.text())
.then((html) => {
modalBody.innerHTML = html;
modalTitle.innerHTML = title;
})
.catch((error) => {
modalBody.innerHTML = '<p class="text-danger">{% trans 'Error loading form. Please try again later' %}.</p>';
console.error("Error loading form:", error);
});
});
});
let Toast = Swal.mixin({ let Toast = Swal.mixin({
toast: true, toast: true,
position: "top-end", position: "top-end",
@ -723,5 +739,6 @@
titleText: msg titleText: msg
}); });
} }
});
</script> </script>
{% endblock customJS %} {% endblock customJS %}

View File

@ -240,7 +240,7 @@
</td> {% endcomment %} </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.slug %}">
<span class="badge badge-phoenix badge-phoenix-success">Opportunity {{ lead.opportunity.lead}} <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>
{% endif %} {% endif %}
@ -260,15 +260,15 @@
</button> </button>
<div class="dropdown-menu dropdown-menu-end py-2"> <div class="dropdown-menu dropdown-menu-end py-2">
{% if perms.inventory.change_lead %} {% if perms.inventory.change_lead %}
<a href="{% url 'lead_update' lead.id %}" class="dropdown-item text-success-dark">{% trans "Edit" %}</a> <a href="{% url 'lead_update' lead.slug %}" class="dropdown-item text-success-dark">{% trans "Edit" %}</a>
{% endif %} {% endif %}
<button class="dropdown-item text-primary" onclick="openActionModal('{{ lead.id }}', '{{ lead.action }}', '{{ lead.next_action }}', '{{ lead.next_action_date|date:"Y-m-d\TH:i" }}')"> <button class="dropdown-item text-primary" onclick="openActionModal('{{ lead.pk }}', '{{ lead.action }}', '{{ lead.next_action }}', '{{ lead.next_action_date|date:"Y-m-d\TH:i" }}')">
{% trans "Update Actions" %} {% trans "Update Actions" %}
</button> </button>
<a href="{% url 'send_lead_email' lead.id %}" class="dropdown-item text-success-dark">{% trans "Send Email" %}</a> <a href="{% url 'send_lead_email' lead.slug %}" class="dropdown-item text-success-dark">{% trans "Send Email" %}</a>
<a href="{% url 'schedule_lead' lead.id %}" class="dropdown-item text-success-dark">{% trans "Schedule Event" %}</a> <a href="{% url 'schedule_lead' lead.slug %}" class="dropdown-item text-success-dark">{% trans "Schedule Event" %}</a>
{% if not lead.opportunity %} {% if not lead.opportunity %}
<a href="{% url 'lead_convert' lead.id %}" class="dropdown-item text-success-dark">{% trans "Convert" %}</a> <a href="{% url 'lead_opportunity_create' lead.slug %}" class="dropdown-item text-success-dark">{% trans "Convert to Opportunity" %}</a>
{% endif %} {% endif %}
<div class="dropdown-divider"></div> <div class="dropdown-divider"></div>
{% if perms.inventory.delete_lead %} {% if perms.inventory.delete_lead %}

View File

@ -3,7 +3,7 @@
{% 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.slug %}" enctype="multipart/form-data">
{% endif %} {% endif %}
{% csrf_token %} {% csrf_token %}

View File

@ -18,7 +18,7 @@
<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" href="{% url 'update_opportunity' opportunity.pk %}">Update Opportunity</a></li> <li><a class="dropdown-item" href="{% url 'update_opportunity' opportunity.slug %}">Update Opportunity</a></li>
<li><a class="dropdown-item text-danger" href="">Delete Opportunity</a></li> <li><a class="dropdown-item text-danger" href="">Delete Opportunity</a></li>
</ul> </ul>
</div> </div>
@ -79,7 +79,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="card"> {% comment %} <div class="card">
<div class="card-body"> <div class="card-body">
<h4 class="mb-5">{{ _("Other Information")}}</h4> <h4 class="mb-5">{{ _("Other Information")}}</h4>
<div class="row g-3"> <div class="row g-3">
@ -101,7 +101,7 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div> {% endcomment %}
</div> </div>
</div> </div>
<div class="col-xl-7 col-xxl-8"> <div class="col-xl-7 col-xxl-8">
@ -330,7 +330,7 @@
</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">
<h2 class="mb-4">Notes</h2> <h2 class="mb-4">Notes</h2>
<form action="{% url 'add_note_to_opportunity' opportunity.pk %}" method="post"> <form action="{% url 'add_note_to_opportunity' opportunity.slug %}" method="post">
{% csrf_token %} {% csrf_token %}
<textarea class="form-control mb-3" id="notes" rows="4" name="notes" required> </textarea> <textarea class="form-control mb-3" id="notes" rows="4" name="notes" required> </textarea>
<button type="submit" class="btn btn-primary mb-3">Add Note</button> <button type="submit" class="btn btn-primary mb-3">Add Note</button>
@ -366,7 +366,7 @@
<button class="btn btn-link p-0 ms-3 fs-9 text-primary fw-bold text-decoration-none"><span class="fas fa-sort me-1 fw-extra-bold fs-10"></span>Sorting</button> <button class="btn btn-link p-0 ms-3 fs-9 text-primary fw-bold text-decoration-none"><span class="fas fa-sort me-1 fw-extra-bold fs-10"></span>Sorting</button>
</div> </div>
<div class="col-auto"> <div class="col-auto">
<a href="{% url 'schedule_lead' opportunity.lead.id %}" class="btn btn-primary"><span class="fa-solid fa-plus me-2"></span>Add Meeting </a> <a href="{% url 'schedule_lead' opportunity.lead.slug %}" class="btn btn-primary"><span class="fa-solid fa-plus me-2"></span>Add Meeting </a>
</div> </div>
</div> </div>
<div class="row g-3"> <div class="row g-3">
@ -394,7 +394,7 @@
</div> </div>
<div class="col-auto"> <div class="col-auto">
<a href="{% url 'schedule_lead' opportunity.lead.id %}" class="btn btn-primary"><span class="fa-solid fa-plus me-2"></span>Add Call</a> <a href="{% url 'schedule_lead' opportunity.lead.slug %}" class="btn btn-primary"><span class="fa-solid fa-plus me-2"></span>Add Call</a>
</div> </div>
</div> </div>
<div class="border-top border-bottom border-translucent" id="leadDetailsTable" data-list='{"valueNames":["name","description","create_date","create_by","last_activity"],"page":5,"pagination":true}'> <div class="border-top border-bottom border-translucent" id="leadDetailsTable" data-list='{"valueNames":["name","description","create_date","create_by","last_activity"],"page":5,"pagination":true}'>
@ -553,5 +553,5 @@
</div> </div>
</div> </div>
</div> </div>
{% include "components/activity_modal.html" with content_type="opportunity" pk=opportunity.pk %} {% include "components/activity_modal.html" with content_type="opportunity" slug=opportunity.slug %}
{% endblock %} {% endblock %}

View File

@ -96,10 +96,10 @@
</div> </div>
<div class="d-flex gap-2"> <div class="d-flex gap-2">
<a class="btn btn-sm btn-phoenix-primary" href="{% url 'opportunity_detail' opportunity.pk %}"> <a class="btn btn-sm btn-phoenix-primary" href="{% url 'opportunity_detail' opportunity.slug %}">
{{ _("View Details") }} <i class="fa-solid fa-eye ms-2"></i> {{ _("View Details") }} <i class="fa-solid fa-eye ms-2"></i>
</a> </a>
<a class="btn btn-sm btn-phoenix-success" href="{% url 'update_opportunity' opportunity.pk %}"> <a class="btn btn-sm btn-phoenix-success" href="{% url 'update_opportunity' opportunity.slug %}">
{{ _("Update") }} <i class="fa-solid fa-pen ms-2"></i> {{ _("Update") }} <i class="fa-solid fa-pen ms-2"></i>
</a> </a>
</div> </div>

View File

@ -1,6 +1,6 @@
{% load i18n static crispy_forms_filters %} {% load i18n static crispy_forms_filters %}
<form method="post" action="{% url 'add_note_to_customer' customer.pk %}" enctype="multipart/form-data"> <form method="post" action="{% url 'add_note_to_customer' customer.slug %}" enctype="multipart/form-data">
{% csrf_token %} {% csrf_token %}
{{ form|crispy }} {{ form|crispy }}
<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>

View File

@ -4,48 +4,101 @@
{% block title %}{{ _("Expenses") }}{% endblock title %} {% block title %}{{ _("Expenses") }}{% endblock title %}
{% block content %} {% block content %}
<div class="row mt-4 mx-4">
<div class="d-flex justify-content-between mb-2 p-6"> <div class="row mt-4">
<span></span>
<h3 class="text-center">{% trans "Expenses" %}</h3> <div class="d-flex justify-content-between mb-2">
<h3 class="">{% trans "Expenses" %}</h3>
<a href="{% url 'item_expense_create' %}" class="btn btn-md btn-phoenix-primary"><i class="fa fa-plus me-2"></i>{% trans "Add Expense" %}</a> <a href="{% url 'item_expense_create' %}" class="btn btn-md btn-phoenix-primary"><i class="fa fa-plus me-2"></i>{% trans "Add Expense" %}</a>
</div> </div>
<div class="mx-n4 px-4 mx-lg-n6 px-lg-6 pt-7 border-y">
<div class="table-responsive mx-n1 px-1 scrollbar"> <div class="col-12">
<table class="table fs-9 mb-0 border-top border-translucent"> <form method="get" class=" mb-4">
<thead> <div class="input-group input-group-sm">
<tr> <button class="btn btn-sm btn-secondary rounded-start" type="submit">
{% trans "search" %}
</button>
<input type="text"
name="q"
class="form-control form-control-sm rounded-end"
value="{{ request.GET.q }}"
placeholder="{% trans 'Search bank accounts...' %}" />
{% if request.GET.q %}
<a href="{% url request.resolver_match.view_name %}"
class="btn btn-sm btn-outline-danger ms-1 rounded">
<i class="bi bi-x-lg"></i>
</a>
{% endif %}
</div>
</form>
</div>
{% if page_obj.object_list %}
<div class="table-responsive px-1 scrollbar mt-3">
<table class="table align-items-center table-flush">
<thead>
<tr class="bg-body-highlight">
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Item Number" %}</th> <th class="sort white-space-nowrap align-middle" scope="col">{% trans "Item Number" %}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Name" %}</th> <th class="sort white-space-nowrap align-middle" scope="col">{% trans "Name" %}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Unit of Measure" %}</th> <th class="sort white-space-nowrap align-middle" scope="col">{% trans "Unit of Measure" %}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Action" %}</th> <th class="sort white-space-nowrap align-middle" scope="col">{% trans "Action" %}</th>
</tr> </tr>
</thead> </thead>
<tbody class="list">
{% for expense in expenses %} <tbody class="list">
<tr class="hover-actions-trigger btn-reveal-trigger position-static">
<td class="align-middle product white-space-nowrap py-0">{{ expense.item_number }}</td> {% for expense in expenses %}
<td class="align-middle product white-space-nowrap">{{ expense.name }}</td>
<td class="align-middle product white-space-nowrap">{{ expense.uom }}</td> <tr class="hover-actions-trigger btn-reveal-trigger position-static">
<td class=""> <td class="align-middle product white-space-nowrap">
<a href="{% url 'item_expense_update' expense.pk %}" {{ expense.item_number }}
</td>
<td class="align-middle product white-space-nowrap">
{{ expense.name }}
</td>
<td class="align-middle product white-space-nowrap">
{{ expense.uom }}
</td>
<td class="align-middle product white-space-nowrap">
<a href="{% url 'item_expense_update' expense.pk %}"
class="btn btn-sm btn-phoenix-success"> class="btn btn-sm btn-phoenix-success">
{% trans "Update" %} {% trans "Update" %}
</a> </a>
</td> </td>
</tr> <td class="align-middle product white-space-nowrap">
</td>
<td class="align-middle white-space-nowrap text-start">
</td>
</tr>
{% empty %} {% empty %}
<tr> <tr>
<td colspan="6" class="text-center">{% trans "No Invoice Found" %}</td> <td colspan="6" class="text-center text-muted">{% trans "No Accounts Found" %}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
</div> </div>
<div class="d-flex justify-content-center">
<div class="d-flex justify-content-between mt-3"><span class="d-none d-sm-inline-block" data-list-info="data-list-info">{{ page_obj.start_index }} {{ _("to") }} {{ page_obj.end_index }}<span class="text-body-tertiary"> {{ _("Items of")}} </span>{{ page_obj.paginator.count }}</span>
<div class="d-flex">
{% if is_paginated %}
{% include 'partials/pagination.html' %}
{% endif %}
</div> </div>
</div> </div>
{% endif %}
</div> </div>
{% endblock %} {% endblock %}

View File

@ -1,22 +1,44 @@
{% extends "base.html" %} {% extends "base.html" %}
{% load i18n static %} {% load i18n static %}
{% block title %}{{ _("Expenses") }}{% endblock title %} {% block title %}{{ _("Services") }}{% endblock title %}
{% block content %} {% block content %}
<div class="row">
<div class="d-flex justify-content-between"> <div class="row mt-4">
<h3 class="mb-2">{% trans "Services" %}</h3> <div class="d-flex justify-content-between mb-2">
<a href="{% url 'item_service_create' %}" class="btn btn-md btn-phoenix-primary"><i class="fa fa-plus me-2"></i>{% trans "Add Service" %}</a> <h3 class="">{% trans "Services" %}</h3>
<a href="{% url 'item_service_create' %}" class="btn btn-md btn-phoenix-primary"><i class="fa fa-plus me-2"></i>{% trans "Add Service" %}</a>
</div>
<div class="col-12">
<form method="get" class=" mb-4">
<div class="input-group input-group-sm">
<button class="btn btn-sm btn-secondary rounded-start" type="submit">
{% trans "search" %}
</button>
<input type="text"
name="q"
class="form-control form-control-sm rounded-end"
value="{{ request.GET.q }}"
placeholder="{% trans 'Search bank accounts...' %}" />
{% if request.GET.q %}
<a href="{% url request.resolver_match.view_name %}"
class="btn btn-sm btn-outline-danger ms-1 rounded">
<i class="bi bi-x-lg"></i>
</a>
{% endif %}
</div>
</form>
</div> </div>
<div class="table-responsive scrollbar transition"> {% if page_obj.object_list %}
<table class="table table-sm fs-9 mb-0 border-translucent"> <div class="table-responsive px-1 scrollbar mt-3">
<table class="table align-items-center table-flush">
<thead> <thead>
<tr> <tr class="bg-body-highlight">
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Item Number" %}</th> <th class="sort white-space-nowrap align-middle" scope="col">{% trans "Item Number" %}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Name" %}</th> <th class="sort white-space-nowrap align-middle" scope="col">{% trans "Name" %}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Unit of Measure" %}</th> <th class="sort white-space-nowrap align-middle" scope="col">{% trans "Unit of Measure" %}</th>
@ -25,36 +47,61 @@
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Action" %}</th> <th class="sort white-space-nowrap align-middle" scope="col">{% trans "Action" %}</th>
</tr> </tr>
</thead> </thead>
<tbody class="list"> <tbody class="list">
{% for service in services %} {% for service in services %}
<tr class="hover-actions-trigger btn-reveal-trigger position-static"> <tr class="hover-actions-trigger btn-reveal-trigger position-static">
<td class="align-middle product white-space-nowrap py-0">{{ service.pk }}</td>
<td class="align-middle product white-space-nowrap">{{ service.get_local_name }}</td>
<td class="align-middle product white-space-nowrap">{{ service.uom }}</td>
<td class="align-middle product white-space-nowrap"> <td class="align-middle product white-space-nowrap">
{% if service.taxable %} {{ service.pk }}
Yes
{% else %}
No
{% endif %}
</td> </td>
<td class="align-middle product white-space-nowrap">{{ service.item.co }}</td> <td class="align-middle product white-space-nowrap">
<td class="text-center"> {{ service.get_local_name }}
<a href="{% url 'item_service_update' service.pk %}" </td>
<td class="align-middle product white-space-nowrap">
{{ service.uom }}
</td>
<td class="align-middle product white-space-nowrap">
{% if service.taxable %}
Yes
{% else %}
No
{% endif %}
</td>
<td class="align-middle product white-space-nowrap">
{{ service.item.co }}
</td>
<td class="align-middle white-space-nowrap text-start">
<a href="{% url 'item_service_update' service.pk %}"
class="btn btn-sm btn-phoenix-success"> class="btn btn-sm btn-phoenix-success">
{% trans "Update" %} {% trans "Update" %}
</a> </a>
</td> </td>
</tr> </tr>
{% empty %}
{% empty %}
<tr> <tr>
<td colspan="6" class="text-center">{% trans "No Invoice Found" %}</td> <td colspan="6" class="text-center text-muted">{% trans "No Accounts Found" %}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
</div> </div>
<div class="d-flex justify-content-center">
<div class="d-flex justify-content-between mt-3"><span class="d-none d-sm-inline-block" data-list-info="data-list-info">{{ page_obj.start_index }} {{ _("to") }} {{ page_obj.end_index }}<span class="text-body-tertiary"> {{ _("Items of")}} </span>{{ page_obj.paginator.count }}</span>
<div class="d-flex">
{% if is_paginated %}
{% include 'partials/pagination.html' %}
{% endif %}
</div>
</div> </div>
{% endif %}
</div> </div>
{% endblock %} {% endblock %}

View File

@ -5,52 +5,89 @@
{% block content %} {% block content %}
<div class="row mt-4"> <div class="row mt-4">
<div class="d-flex justify-content-between mb-2">
<h3 class="">{% trans "Bank Accounts" %}</h3> <div class="d-flex justify-content-between mb-2">
<h3 class="">{% trans "Bank Accounts" %}</h3>
<a href="{% url 'bank_account_create' %}" class="btn btn-md btn-phoenix-primary"><i class="fa fa-plus me-2"></i>{% trans "Add Bank Account" %}</a> <a href="{% url 'bank_account_create' %}" class="btn btn-md btn-phoenix-primary"><i class="fa fa-plus me-2"></i>{% trans "Add Bank Account" %}</a>
</div> </div>
<div class="col-12">
<form method="get" class=" mb-4">
<div class="input-group input-group-sm">
<button class="btn btn-sm btn-secondary rounded-start" type="submit">
{% trans "search" %}
</button>
<input type="text"
name="q"
class="form-control form-control-sm rounded-end"
value="{{ request.GET.q }}"
placeholder="{% trans 'Search bank accounts...' %}" />
{% if request.GET.q %}
<a href="{% url request.resolver_match.view_name %}"
class="btn btn-sm btn-outline-danger ms-1 rounded">
<i class="bi bi-x-lg"></i>
</a>
{% endif %}
</div>
</form>
</div>
{% if page_obj.object_list %}
<div class="table-responsive px-1 scrollbar mt-3"> <div class="table-responsive px-1 scrollbar mt-3">
<table class="table align-items-center table-flush"> <table class="table align-items-center table-flush">
<thead> <thead>
<tr class="bg-body-highlight"> <tr class="bg-body-highlight">
<th class="border-top border-translucent ps-3">{% trans "Name" %}</th> <th class="sort white-space-nowrap align-middle" scope="col">{% trans "Name" %}</th>
<th class="border-top border-translucent ps-3">{% trans "Account Number" %}</th> <th class="sort white-space-nowrap align-middle" scope="col">{% trans "Account Number" %}</th>
<th class="border-top border-translucent text-end pe-3">{% trans "Type" %}</th> <th class="sort white-space-nowrap align-middle" scope="col">{% trans "Type" %}</th>
<th class="border-top border-translucent text-end pe-3" scope="col">{% trans "Action" %}</th> <th class="sort white-space-nowrap align-middle" scope="col">{% trans "Action" %}</th>
</tr> </tr>
</thead> </thead>
<tbody class="list"> <tbody class="list">
{% for bank in bank_accounts %} {% for bank in bank_accounts %}
<tr class="hover-actions-trigger btn-reveal-trigger position-static"> <tr class="hover-actions-trigger btn-reveal-trigger position-static">
<td class="align-middle ps-3">{{ bank.name }}</td> <td class="align-middle product white-space-nowrap">
<td class="align-middle ps-3">{{ bank.account_number }}</td> {{ bank.name }}
<td class="align-middle product text-end pe-3 ">{{ bank.account_type|capfirst }}</td> </td>
<td class="align-middle product text-end pe-3 "> <td class="align-middle product white-space-nowrap">
<a href="{% url 'bank_account_update' bank.pk %}" {{ bank.account_number }}
</td>
<td class="align-middle product white-space-nowrap">
{{ bank.account_type|capfirst }}
</td>
<td class="align-middle product white-space-nowrap">
<a href="{% url 'bank_account_update' bank.pk %}"
class="btn btn-sm btn-phoenix-success"> class="btn btn-sm btn-phoenix-success">
{% trans "Update" %} {% trans "Update" %}
</a> </a>
</td> </td>
</tr> </tr>
{% empty %} {% empty %}
<tr> <tr>
<td colspan="6" class="text-center">{% trans "No Bank Accounts Found" %}</td> <td colspan="6" class="text-center text-muted">{% trans "No Accounts Found" %}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
</div> </div>
<div class="d-flex justify-content-center"> <div class="d-flex justify-content-between mt-3"><span class="d-none d-sm-inline-block" data-list-info="data-list-info">{{ page_obj.start_index }} {{ _("to") }} {{ page_obj.end_index }}<span class="text-body-tertiary"> {{ _("Items of")}} </span>{{ page_obj.paginator.count }}</span>
<div class="d-flex">
{% if is_paginated %}
{% include 'partials/pagination.html' %}
{% endif %}
</div>
</div> </div>
{% endif %}
</div> </div>
{% endblock %} {% endblock %}

View File

@ -10,129 +10,102 @@
</a> </a>
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div class="d-flex flex-column min-vh-100">
<div class="d-grid gap-2 d-md-flex justify-content-md-end"> <div class="row mt-4">
<a href="{% url 'bill_create' %}" class="btn btn-md btn-phoenix-primary"> <div class="d-flex justify-content-between mb-2">
<i class="fa fa-plus me-2"></i> <h3 class="">{% trans "Bills" %}</h3>
{% trans 'New Bill' %}</a> <a href="{% url 'bill_create' %}" class="btn btn-md btn-phoenix-primary"><i class="fa fa-plus me-2"></i>{% trans 'New Bill' %}</a>
</div> </div>
<div class="d-flex flex-column flex-sm-grow-1 p-4">
<main class="d-grid gap-4 p-1">
<!-- Search Bar -->
<div class="row g-4"> <div class="col-12">
<div class="col-12"> <form method="get" class=" mb-4">
<div class="row-fluid p-2">
<form method="get">
<div class="input-group input-group-sm"> <div class="input-group input-group-sm">
<button class="btn btn-sm btn-secondary rounded-start" type="submit">{% trans 'search' %}</button> <button class="btn btn-sm btn-secondary rounded-start" type="submit">
<input type="text" name="q" class="form-control form-control-sm rounded-end" value="{{ request.GET.q }}" placeholder="{% trans 'Search bills...' %}" /> {% trans "search" %}
{% if request.GET.q %} </button>
<a href="{% url request.resolver_match.view_name %}" class="btn btn-sm btn-outline-danger ms-1 rounded"><i class="bi bi-x-lg"></i></a> <input type="text"
{% endif %} name="q"
</div> class="form-control form-control-sm rounded-end"
</form> value="{{ request.GET.q }}"
</div> placeholder="{% trans 'Search bills...' %}" />
</div> {% if request.GET.q %}
</div> <a href="{% url request.resolver_match.view_name %}"
class="btn btn-sm btn-outline-danger ms-1 rounded">
<!-- Customer Table --> <i class="bi bi-x-lg"></i>
<div id="accountsTable"> </a>
<div class="table-responsive">
<table class="table table-sm fs-9 mb-0">
<thead>
<tr class="bg-body-highlight">
<th class="border-top border-translucent ps-3">
{% trans 'Bill Number' %}
</th>
<th class="border-top border-translucent">
{% trans 'Bill Status' %}
</th>
<th class="border-top border-translucent text-end pe-3">
{% trans 'Vendor' %}
</th>
<th class="border-top border-translucent text-end pe-3" scope="col">Action</th>
</tr>
</thead>
<tbody class="list">
{% for bill in bills %}
<tr>
<td class="align-middle ps-3">{{ bill.bill_number }}</td>
<td class="align-middle">
{% if bill.is_draft %}
<span class="badge badge-phoenix badge-phoenix-warning">
{% elif bill.is_review %}
<span class="badge badge-phoenix badge-phoenix-info">
{% elif bill.is_approved %}
<span class="badge badge-phoenix badge-phoenix-success">
{% elif bill.is_paid %}
<span class="badge badge-phoenix badge-phoenix-success">
{% endif %}
{{ bill.bill_status }}
</span>
</td>
<td class="align-middle text-end py-3 pe-3">
{{bill.vendor.vendor_name}}
</td>
<td class="align-middle text-end py-3 pe-3">
<div class="btn-reveal-trigger position-static">
<button class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10" type="button" data-bs-toggle="dropdown" data-boundary="window" aria-haspopup="true" aria-expanded="false" data-bs-reference="parent"><span class="fas fa-ellipsis-h fs-10"></span></button>
<div class="dropdown-menu dropdown-menu-end py-2">
<a href="{% url 'bill_detail' bill.pk %}" class="dropdown-item text-success-dark">{% trans 'View' %}</a>
</div>
</div>
</td>
</tr>
{% empty %}
<tr>
<td colspan="5" class="text-center text-muted">
{% trans 'No bill found.' %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="d-flex justify-content-between mt-3">
<span class="d-none d-sm-inline-block" data-list-info="data-list-info">{{ page_obj.start_index }} {{ _('to') }} {{ page_obj.end_index }}<span class="text-body-tertiary">{{ _('Items of') }}</span>{{ page_obj.paginator.count }}</span>
<div class="d-flex">
<nav aria-label="Page navigation">
<ul class="pagination mb-0">
{% if page_obj.has_previous %}
<li class="page-item py-0">
<a class="page-link" href="?page={{ page_obj.previous_page_number }}" aria-label="Previous"><span aria-hidden="true"><span class="fas fa-chevron-left"></span></span></a>
</li>
{% else %}
<li class="page-item disabled">
<a class="page-link" href="#" aria-label="Previous"><span aria-hidden="true"><span class="fas fa-chevron-left"></span></span></a>
</li>
{% endif %}
{% for num in page_obj.paginator.page_range %}
{% if page_obj.number == num %}
<li class="page-item active">
<a class="page-link" href="?page={{ num }}">{{ num }}</a>
</li>
{% else %}
<li class="page-item">
<a class="page-link" href="?page={{ num }}">{{ num }}</a>
</li>
{% endif %} {% endif %}
{% endfor %} </div>
{% if page_obj.has_next %} </form>
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.next_page_number }}" aria-label="Next"><span aria-hidden="true"><span class="fas fa-chevron-right"></span></span></a>
</li>
{% else %}
<li class="page-item disabled">
<a class="page-link" href="#" aria-label="Next"><span aria-hidden="true"><span class="fas fa-chevron-right"></span></span></a>
</li>
{% endif %}
</ul>
</nav>
</div>
</div>
</div> </div>
</main>
<div class="table-responsive px-1 scrollbar mt-3">
<table class="table align-items-center table-flush">
<thead>
<tr class="bg-body-highlight">
<th class="sort white-space-nowrap align-middle" scope="col">{% trans 'Bill Number' %}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{% trans 'Bill Status' %}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{% trans 'Vendor' %}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{% trans 'Action'%}</th>
</tr>
</thead>
<tbody class="list">
{% for bill in bills %}
<tr class="hover-actions-trigger btn-reveal-trigger position-static">
<td class="align-middle product white-space-nowrap">
{{ bill.bill_number }}
</td>
<td class="align-middle product white-space-nowrap">
{% if bill.is_draft %}
<span class="badge badge-phoenix badge-phoenix-warning">
{% elif bill.is_review %}
<span class="badge badge-phoenix badge-phoenix-info">
{% elif bill.is_approved %}
<span class="badge badge-phoenix badge-phoenix-success">
{% elif bill.is_paid %}
<span class="badge badge-phoenix badge-phoenix-success">
{% endif %}
{{ bill.bill_status }}
</span>
</td>
<td class="align-middle product white-space-nowrap">
{{bill.vendor.vendor_name}}
</td>
<td class="align-middle product white-space-nowrap">
<div class="btn-reveal-trigger position-static">
<button class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10" type="button" data-bs-toggle="dropdown" data-boundary="window" aria-haspopup="true" aria-expanded="false" data-bs-reference="parent"><span class="fas fa-ellipsis-h fs-10"></span></button>
<div class="dropdown-menu dropdown-menu-end py-2">
<a href="{% url 'bill_detail' bill.pk %}" class="dropdown-item text-success-dark">{% trans 'View' %}</a>
</div>
</div>
</tr>
{% empty %}
<tr>
<td colspan="5" class="text-center text-muted">
{% trans 'No bill found.' %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="d-flex justify-content-between mt-3"><span class="d-none d-sm-inline-block" data-list-info="data-list-info">{{ page_obj.start_index }} {{ _("to") }} {{ page_obj.end_index }}<span class="text-body-tertiary"> {{ _("Items of")}} </span>{{ page_obj.paginator.count }}</span>
<div class="d-flex">
{% if is_paginated %}
{% include 'partials/pagination.html' %}
{% endif %}
</div>
</div>
</div> </div>
</div>
{% endblock %} {% endblock %}

View File

@ -6,7 +6,7 @@
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<!-- Delete Modal -->
<div class="modal fade" id="deleteModal" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="deleteModalLabel" aria-hidden="true"> <div class="modal fade" id="deleteModal" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="deleteModalLabel" aria-hidden="true">
<div class="modal-dialog modal-sm"> <div class="modal-dialog modal-sm">
<div class="modal-content rounded"> <div class="modal-content rounded">
@ -56,58 +56,82 @@
</p> </p>
</div> </div>
</div> </div>
<div class="row">
<div class="table-responsive"> <div class="row mt-4">
<table class="table table-sm fs-9 mb-0">
<tr> <div class="table-responsive px-1 scrollbar mt-3">
<th class="has-text-centered">{{ _('JE Number') }}</th> <table class="table align-items-center table-flush">
<th class="has-text-centered">{{ _('Date') }}</th> <thead>
<th class="has-text-centered">{{ _('Debit') }}</th> <tr class="bg-body-highlight">
<th class="has-text-centered">{{ _('Credit') }}</th> <th class="sort white-space-nowrap align-middle" scope="col">{{ _('JE Number') }}</th>
<th class="has-text-centered">{{ _('Description') }}</th> <th class="sort white-space-nowrap align-middle" scope="col">{{ _('Date') }}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{{ _('Debit') }}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{{ _('Credit') }}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{{ _('Description') }}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{{ _('Actions') }}</th>
</tr>
</thead>
<tbody class="list">
{% for tx in account.transactionmodel_set.all %}
<tr class="hover-actions-trigger btn-reveal-trigger position-static">
<td class="align-middle product white-space-nowrap">
{{ tx.journal_entry.je_number }}
</td>
<td class="align-middle product white-space-nowrap">
{{ tx.journal_entry.timestamp }}
</td>
<td class="align-middle product white-space-nowrap">
{% if tx.tx_type == 'debit' %}
<i class="fa-solid fa-circle-up"></i> {{ tx.amount }}
{% endif %}
</td>
<td class="align-middle product white-space-nowrap">
{% if tx.tx_type == 'credit' %}
<i class="fa-solid fa-circle-down"></i> {{ tx.amount }}
{% endif %}
</td>
<td class="align-middle product white-space-nowrap">
{{ tx.description }}
</td>
<td class="align-middle white-space-nowrap text-start">
<div class="btn-reveal-trigger position-static">
<button class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10" type="button" data-bs-toggle="dropdown" data-boundary="window" aria-haspopup="true" aria-expanded="false" data-bs-reference="parent"><span class="fas fa-ellipsis-h fs-10"></span></button>
<div class="dropdown-menu dropdown-menu-end py-2">
<a class="dropdown-item" href="{% url 'payment_details' tx.journal_entry.pk %}">{% trans 'view'|capfirst %}</a>
</div>
</div>
</td>
</tr>
{% endfor %}
<th class="has-text-centered">{{ _('Actions') }}</th> <tr class="hover-actions-trigger btn-reveal-trigger position-static">
</tr> <td class="align-middle product white-space-nowrap">
{% for tx in account.transactionmodel_set.all %} </td>
<tr class="has-text-centered"> <td class="align-middle product white-space-nowrap">
<td>{{ tx.journal_entry.je_number }}</td> <span class="fw-bold fs-8">{{ _("Total") }}</span>
<td>{{ tx.journal_entry.timestamp }}</td> </td>
<td class="text-success"> <td class="align-middle product white-space-nowrap">
{% if tx.tx_type == 'debit' %} <span class="fw-bold fs-8 text-success">{{ total_debits }} <span class="currency">{{ CURRENCY }}</span></span>
<i class="fa-solid fa-circle-up"></i> {{ tx.amount }} </td>
{% endif %} <td class="align-middle product white-space-nowrap">
</td> <span class="fw-bold fs-8 text-danger">{{ total_credits }} <span class="currency">{{ CURRENCY }}</span></span>
<td class="text-danger"> </td>
{% if tx.tx_type == 'credit' %} <td class="align-middle product white-space-nowrap">
<i class="fa-solid fa-circle-down"></i> {{ tx.amount }}
{% endif %} </td>
</td> <td class="align-middle white-space-nowrap text-start">
<td>{{ tx.description }}</td>
</td>
<td> </tr>
<div class="btn-reveal-trigger position-static">
<button class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10" type="button" data-bs-toggle="dropdown" data-boundary="window" aria-haspopup="true" aria-expanded="false" data-bs-reference="parent"><span class="fas fa-ellipsis-h fs-10"></span></button> </tbody>
<div class="dropdown-menu dropdown-menu-end py-2">
<a class="dropdown-item" href="{% url 'payment_details' tx.journal_entry.pk %}">{% trans 'view'|capfirst %}</a>
</div>
</div>
</td>
</tr>
{% endfor %}
<tr class="has-text-weight-bold">
<td></td>
<td class="has-text-right"><span class="fw-bold fs-8">{{ _("Total") }}</span></td>
<td class="has-text-centered"><span class="fw-bold fs-8 text-success">{{ total_debits }} <span class="currency">{{ CURRENCY }}</span></span></td>
<td class="has-text-centered"><span class="fw-bold fs-8 text-danger">{{ total_credits }} <span class="currency">{{ CURRENCY }}</span></span></td>
<td></td>
<td></td>
<td></td>
</tr>
</table> </table>
</div>
</div> </div>
</div>
</div>
<div class="mt-3 d-flex"> <div class="mt-3 d-flex">
<a class="btn btn-sm btn-phoenix-primary me-1" href="{% url 'account_update' account.pk %}"> <a class="btn btn-sm btn-phoenix-primary me-1" href="{% url 'account_update' account.pk %}">
<!-- <i class="bi bi-pencil-square"></i> --> <!-- <i class="bi bi-pencil-square"></i> -->
@ -122,6 +146,8 @@
<i class="fa-regular fa-circle-left"></i> {% trans 'Back to List' %} <i class="fa-regular fa-circle-left"></i> {% trans 'Back to List' %}
</a> </a>
</div> </div>
</div> </div>
</div> </div>
<!--test-->
{% endblock %} {% endblock %}

View File

@ -8,16 +8,12 @@
</a> </a>
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<!--test-->
<!-- Search Bar -->
<div class="row mt-4"> <div class="row mt-4">
<div class="d-grid gap-2 d-md-flex justify-content-md-end"> <div class="d-flex justify-content-between mb-2">
<a href="{% url 'account_create' %}" class="btn btn-md btn-phoenix-primary"> <h3 class=""><i class="fa-solid fa-book"></i> {% trans "Accounts" %}</h3>
<i class="fa fa-plus me-2"></i> <a href="{% url 'account_create' %}" class="btn btn-md btn-phoenix-primary"><i class="fa fa-plus me-2"></i>{% trans 'New Account' %}</a>
{% trans 'New Account' %}</a>
</div> </div>
<h3 class="mb-3">
<i class="fa-solid fa-book"></i> {% trans "Accounts" %}</h3>
<div class="col-12"> <div class="col-12">
<form method="get" class=" mb-4"> <form method="get" class=" mb-4">
<div class="input-group input-group-sm"> <div class="input-group input-group-sm">
@ -38,25 +34,24 @@
</div> </div>
</form> </form>
</div> </div>
</div>
{% if page_obj.object_list %}
{% if page_obj.object_list %}
<div class="table-responsive px-1 scrollbar mt-3"> <div class="table-responsive px-1 scrollbar mt-3">
<table class="table align-items-center table-flush"> <table class="table align-items-center table-flush">
<thead> <thead>
<tr class="bg-body-highlight"> <tr class="bg-body-highlight">
<th class="border-top border-translucent">{% trans "Type" %}</th> <th class="sort white-space-nowrap align-middle" scope="col">{% trans "Type" %}</th>
<th class="border-top border-translucent ps-3">{% trans "Account Name" %}</th> <th class="sort white-space-nowrap align-middle" scope="col">{% trans "Account Name" %}</th>
<th class="border-top border-translucent">{% trans "Code" %}</th> <th class="sort white-space-nowrap align-middle" scope="col">{% trans "Code" %}</th>
<th class="border-top border-translucent text-end pe-3">{% trans "Balance Type" %}</th> <th class="sort white-space-nowrap align-middle" scope="col">{% trans "Balance Type" %}</th>
<th class="border-top border-translucent text-end pe-3">{% trans "Active" %}</th> <th class="sort white-space-nowrap align-middle" scope="col">{% trans "Active" %}</th>
<th class="border-top border-translucent text-end align-middle pe-0 ps-4" scope="col"></th> <th class="sort white-space-nowrap align-middle" scope="col"></th>
</tr> </tr>
</thead> </thead>
<tbody class="list"> <tbody class="list">
{% for account in accounts %} {% for account in accounts %}
<div class="modal fade" id="deleteModal" <div class="modal fade" id="deleteModal"
data-bs-backdrop="static" data-bs-backdrop="static"
@ -91,26 +86,33 @@
</div> </div>
</div> </div>
</div> </div>
<tr>
<td class="align-middle ps-3 fw-lighter">{{ account.role_bs|upper }}</td>
<td class="align-middle ps-3">{{ account.name }}</td>
<td class="align-middle">{{ account.code }}</td>
<td class="align-middle text-end py-3 pe-3">
<tr class="hover-actions-trigger btn-reveal-trigger position-static">
<td class="align-middle product white-space-nowrap">
{{ account.role_bs|upper }}
</td>
<td class="align-middle product white-space-nowrap">
{{ account.name }}
</td>
<td class="align-middle product white-space-nowrap">
{{ account.code }}
</td>
<td class="align-middle product white-space-nowrap">
{% if account.balance_type == 'debit' %} {% if account.balance_type == 'debit' %}
<div class="badge badge-phoenix fs-10 badge-phoenix-success"><span class="fw-bold"><i class="fa-solid fa-circle-up"></i> {{ _("Debit") }}</span></div> <div class="badge badge-phoenix fs-10 badge-phoenix-success"><span class="fw-bold"><i class="fa-solid fa-circle-up"></i> {{ _("Debit") }}</span></div>
{% else %} {% else %}
<div class="badge badge-phoenix fs-10 badge-phoenix-danger"><span class="fw-bold"><i class="fa-solid fa-circle-down"></i> {{ _("Credit") }}</span></div> <div class="badge badge-phoenix fs-10 badge-phoenix-danger"><span class="fw-bold"><i class="fa-solid fa-circle-down"></i> {{ _("Credit") }}</span></div>
{% endif %} {% endif %}
</td> </td>
<td class="align-middle text-end py-3 pe-3"> <td class="align-middle product white-space-nowrap">
{% if account.active %} {% if account.active %}
<span class="fw-bold text-success fas fa-check-circle"></span> <span class="fw-bold text-success fas fa-check-circle"></span>
{% else %} {% else %}
<span class="fw-bold text-danger far fa-times-circle"></span> <span class="fw-bold text-danger far fa-times-circle"></span>
{% endif %} {% endif %}
</td> </td>
<td> <td class="align-middle white-space-nowrap text-start">
<div class="btn-reveal-trigger position-static"> <div class="btn-reveal-trigger position-static">
<button class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10" type="button" data-bs-toggle="dropdown" data-boundary="window" aria-haspopup="true" aria-expanded="false" data-bs-reference="parent"><span class="fas fa-ellipsis-h fs-10"></span></button> <button class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10" type="button" data-bs-toggle="dropdown" data-boundary="window" aria-haspopup="true" aria-expanded="false" data-bs-reference="parent"><span class="fas fa-ellipsis-h fs-10"></span></button>
<div class="dropdown-menu dropdown-menu-end py-2"><a href="{% url 'account_detail' account.uuid %}" class="dropdown-item text-success-dark"> <div class="dropdown-menu dropdown-menu-end py-2"><a href="{% url 'account_detail' account.uuid %}" class="dropdown-item text-success-dark">
@ -118,21 +120,17 @@
</a> </a>
<div class="dropdown-divider"></div><button class="dropdown-item text-danger" data-bs-toggle="modal" data-bs-target="#deleteModal">{% trans "Delete" %}</button> <div class="dropdown-divider"></div><button class="dropdown-item text-danger" data-bs-toggle="modal" data-bs-target="#deleteModal">{% trans "Delete" %}</button>
</div> </div>
</div> </div>
</td> </td>
</tr> </tr>
{% empty %} {% empty %}
<tr> <tr>
<td colspan="5" class="text-center text-muted"> <td colspan="6" class="text-center text-muted">{% trans "No Accounts Found" %}</td>
{% trans "No account found." %}
</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
</div> </div>
<div class="d-flex justify-content-between mt-3"><span class="d-none d-sm-inline-block" data-list-info="data-list-info">{{ page_obj.start_index }} {{ _("to") }} {{ page_obj.end_index }}<span class="text-body-tertiary"> {{ _("Items of")}} </span>{{ page_obj.paginator.count }}</span> <div class="d-flex justify-content-between mt-3"><span class="d-none d-sm-inline-block" data-list-info="data-list-info">{{ page_obj.start_index }} {{ _("to") }} {{ page_obj.end_index }}<span class="text-body-tertiary"> {{ _("Items of")}} </span>{{ page_obj.paginator.count }}</span>
<div class="d-flex"> <div class="d-flex">
@ -142,7 +140,11 @@
</div> </div>
</div> </div>
{% endif %} {% endif %}
{% endblock %} </div>
<!--test-->
{% endblock %}

View File

@ -31,33 +31,20 @@
</div> </div>
</div> </div>
<!--test-->
<div class="row mt-4"> <div class="row mt-4">
<div class="d-flex justify-content-between mb-2">
<h3 class="">{% trans "Journal Entries" %}</h3>
<div class="d-flex gap-2">
{% comment %} {% if ledger.is_posted %}
{% if ledger.is_locked %}
<a class="btn btn-sm btn-phoenix-danger" href="{% url 'unlock_all_journals' ledger.entity_slug ledger.pk %} ">{% trans 'UnLock All' %}</a>
{% else %}
<a class="btn btn-sm btn-phoenix-danger" href="{% url 'lock_all_journals' ledger.entity_slug ledger.pk %} ">{% trans 'Lock All' %}</a>
{% endif %}
{% endif %}
{% if not ledger.is_locked %}
{% if ledger.is_posted %}
<a class="btn btn-sm btn-phoenix-success" href="{% url 'unpost_all_journals' ledger.entity_slug ledger.pk %} ">{% trans 'UnPost All' %}</a>
{% else %}
<a class="btn btn-sm btn-phoenix-success" href="{% url 'post_all_journals' ledger.entity_slug ledger.pk %} ">{% trans 'Post All' %}</a>
{% endif %}
{% endif %} {% endcomment %}
<a href="{% url 'journalentry_create' ledger.pk %}" class="btn btn-sm btn-phoenix-primary">{% trans "Add Journal Entry" %}</a>
</div>
</div>
</div>
<div class="table-responsive px-1 scrollbar"> <div class="d-flex justify-content-between mb-2">
<table class="table fs-9 mb-0 border-top border-translucent"> <h3 class="">{% trans "Journal Entries" %}</h3>
<a href="{% url 'journalentry_create' ledger.pk %}" class="btn btn-md btn-phoenix-primary"><i class="fa fa-plus me-2"></i>{% trans "Add Journal Entry" %}</a>
</div>
<div class="table-responsive px-1 scrollbar">
<table class="table align-items-center table-flush">
<thead> <thead>
<tr> <tr class="bg-body-highlight">
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Document Number" %}</th> <th class="sort white-space-nowrap align-middle" scope="col">{% trans "Document Number" %}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Timestamp" %}</th> <th class="sort white-space-nowrap align-middle" scope="col">{% trans "Timestamp" %}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Activity" %}</th> <th class="sort white-space-nowrap align-middle" scope="col">{% trans "Activity" %}</th>
@ -126,8 +113,10 @@
</tbody> </tbody>
</table> </table>
</div> </div>
<div class="d-flex justify-content-center">
</div>
</div> </div>
<!--test-->
{% endblock %} {% endblock %}

View File

@ -11,9 +11,9 @@
<h3 class="mb-3 mt-5"><i class="fa-solid fa-right-left"></i> {% trans "Transactions" %}</h3> <h3 class="mb-3 mt-5"><i class="fa-solid fa-right-left"></i> {% trans "Transactions" %}</h3>
<div class="table-responsive px-1 scrollbar"> <div class="table-responsive px-1 scrollbar">
<table class="table fs-9 mb-0 border-top border-translucent"> <table class="table align-items-center table-flush">
<thead> <thead>
<tr> <tr class="bg-body-highlight">
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "#" %}</th> <th class="sort white-space-nowrap align-middle" scope="col">{% trans "#" %}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Timestamp" %}</th> <th class="sort white-space-nowrap align-middle" scope="col">{% trans "Timestamp" %}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Account Name" %}</th> <th class="sort white-space-nowrap align-middle" scope="col">{% trans "Account Name" %}</th>

View File

@ -4,18 +4,41 @@
{% block title %}{{ _("Ledger") }}{% endblock title %} {% block title %}{{ _("Ledger") }}{% endblock title %}
{% block content %} {% block content %}
<div class="row mt-4"> <div class="row mt-4">
<div class="d-flex justify-content-between mb-2"> <div class="d-flex justify-content-between mb-2">
<h3 class="">{% trans "Ledger" %}</h3> <h3 class="">{% trans "Ledger" %}</h3>
<a href="{% url 'ledger_create' %}" class="btn btn-md btn-phoenix-primary"><i class="fa fa-plus me-2"></i>{% trans 'Create Ledger' %}</a>
</div> </div>
<div class="d-grid gap-2 d-md-flex justify-content-md-end">
<a href="{% url 'ledger_create' %}" class="btn btn-md btn-phoenix-primary"> <div class="col-12">
<i class="fa fa-plus me-2"></i> <form method="get" class=" mb-4">
{% trans 'Create Ledger' %}</a> <div class="input-group input-group-sm">
<button class="btn btn-sm btn-secondary rounded-start" type="submit">
{% trans "search" %}
</button>
<input type="text"
name="q"
class="form-control form-control-sm rounded-end"
value="{{ request.GET.q }}"
placeholder="{% trans 'Search ledgers...' %}" />
{% if request.GET.q %}
<a href="{% url request.resolver_match.view_name %}"
class="btn btn-sm btn-outline-danger ms-1 rounded">
<i class="bi bi-x-lg"></i>
</a>
{% endif %}
</div>
</form>
</div> </div>
<div class="table-responsive px-1 scrollbar mt-3"> <div class="table-responsive px-1 scrollbar mt-3">
<table class="table fs-9 mb-0 border-top border-translucent"> <table class="table align-items-center table-flush">
<thead> <thead>
<tr class="bg-body-highlight"> <tr class="bg-body-highlight">
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Ledger Name" %}</th> <th class="sort white-space-nowrap align-middle" scope="col">{% trans "Ledger Name" %}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Journal Entries" %}</th> <th class="sort white-space-nowrap align-middle" scope="col">{% trans "Journal Entries" %}</th>
@ -25,11 +48,13 @@
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Action" %}</th> <th class="sort white-space-nowrap align-middle" scope="col">{% trans "Action" %}</th>
</tr> </tr>
</thead> </thead>
<tbody class="list"> <tbody class="list">
{% for ledger in ledgers %} {% for ledger in ledgers %}
<tr class="hover-actions-trigger btn-reveal-trigger position-static"> <tr class="hover-actions-trigger btn-reveal-trigger position-static">
<td class="align-middle product white-space-nowrap"> <td class="align-middle product white-space-nowrap">
{% if ledger.invoicemodel %} {% if ledger.invoicemodel %}
<a href="{% url 'invoice_detail' ledger.invoicemodel.pk %}">{{ ledger.get_wrapped_model_instance }}</a> <a href="{% url 'invoice_detail' ledger.invoicemodel.pk %}">{{ ledger.get_wrapped_model_instance }}</a>
{% elif ledger.billmodel %} {% elif ledger.billmodel %}
<a href="{% url 'bill_detail' ledger.billmodel.pk %}">{{ ledger.get_wrapped_model_instance }}</a> <a href="{% url 'bill_detail' ledger.billmodel.pk %}">{{ ledger.get_wrapped_model_instance }}</a>
@ -38,7 +63,7 @@
{% endif %} {% endif %}
</td> </td>
<td class="align-middle product white-space-nowrap"> <td class="align-middle product white-space-nowrap">
<a class="btn btn-sm btn-primary" <a class="btn btn-sm btn-primary"
href="{% url 'journalentry_list' ledger.pk %}"> href="{% url 'journalentry_list' ledger.pk %}">
<i class="fa-solid fa-right-left"></i> <i class="fa-solid fa-right-left"></i>
<span> <span>
@ -48,21 +73,21 @@
</a> </a>
</td> </td>
<td class="align-middle product white-space-nowrap"> <td class="align-middle product white-space-nowrap">
{{ ledger.created |date }} {{ ledger.created |date }}
</td> </td>
<td class="align-middle product white-space-nowrap"> <td class="align-middle product white-space-nowrap">
{% if ledger.is_posted %} {% if ledger.is_posted %}
<i class="fa-solid fa-square-check text-success"></i> <i class="fa-solid fa-square-check text-success"></i>
{% else %} {% else %}
<i class="fa-solid fa-circle-xmark text-danger"></i> <i class="fa-solid fa-circle-xmark text-danger"></i>
{% endif %} {% endif %}
</td> </td>
<td class="align-middle product white-space-nowrap"> <td class="align-middle product white-space-nowrap">
{% if ledger.is_locked %} {% if ledger.is_locked %}
<i class="fa-solid fa-lock text-success"></i> <i class="fa-solid fa-lock text-success"></i>
{% else %} {% else %}
<i class="fa-solid fa-unlock text-danger"></i> <i class="fa-solid fa-unlock text-danger"></i>
{% endif %} {% endif %}
</td> </td>
<td class="align-middle white-space-nowrap text-start"> <td class="align-middle white-space-nowrap text-start">
<div class="btn-reveal-trigger position-static"> <div class="btn-reveal-trigger position-static">
@ -108,19 +133,30 @@
class="dropdown-item has-text-danger has-text-weight-bold">{% trans 'Delete' %}</a> class="dropdown-item has-text-danger has-text-weight-bold">{% trans 'Delete' %}</a>
{% endif %} {% endif %}
</div> </div>
</div> </div>
</td> </td>
</tr> </tr>
{% empty %} {% empty %}
<tr> <tr>
<td colspan="6" class="text-center">{% trans "No Bank Accounts Found" %}</td> <td colspan="6" class="text-center">{% trans "No Entries found" %}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
</div> </div>
<div class="d-flex justify-content-center">
<div class="d-flex justify-content-between mt-3"><span class="d-none d-sm-inline-block" data-list-info="data-list-info">{{ page_obj.start_index }} {{ _("to") }} {{ page_obj.end_index }}<span class="text-body-tertiary"> {{ _("Items of")}} </span>{{ page_obj.paginator.count }}</span>
<div class="d-flex">
{% if is_paginated %}
{% include 'partials/pagination.html' %}
{% endif %}
</div>
</div> </div>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -5,128 +5,143 @@
{% block vendors %}<a class="nav-link active">{{ _("Vendors")|capfirst }}</a>{% endblock %} {% block vendors %}<a class="nav-link active">{{ _("Vendors")|capfirst }}</a>{% endblock %}
{% block content %} {% block content %}
<section class="pt-5 pb-9">
<div class="row">
<div class="row mt-4">
<h2 class="mb-4">{{ _("Vendors")|capfirst }}</h2> <div class="d-flex justify-content-between mb-2">
<h3 class="">{{ _("Vendors")|capfirst }}</h2>
<div class="row g-3 justify-content-between mb-4"> <a href="{% url 'vendor_create' %}" class="btn btn-md btn-phoenix-primary"><i class="fa fa-plus me-2"></i>{{ _("Add Vendor") }}</a>
<div class="col-auto">
<div class="d-md-flex justify-content-between">
<div>
<a href="{% url 'vendor_create' %}" class="btn btn-md btn-phoenix-primary"><span class="fas fa-plus me-2"></span>{{ _("Add Vendor") }}</a>
</div>
</div>
</div> </div>
<div class="col-auto">
<div class="d-flex">
<div class="search-box me-2">
<form method="get" class="d-inline-block position-relative">
<input name="q" class="form-control search-input search" type="search" placeholder="{{ _('Enter vendor name') }}" aria-label="Search" value="{{ request.GET.q }}"/>
<span class="fas fa-search search-box-icon"></span>
{% if request.GET.q %}
<a href="{% url request.resolver_match.view_name %}" class="btn btn-outline-danger ms-1">
<i class="bi bi-x-lg"></i>
</a>
{% endif %}
</form>
</div>
</div> <div class="col-12">
<form method="get" class=" mb-4">
<div class="input-group input-group-sm">
<button class="btn btn-sm btn-secondary rounded-start" type="submit">
{% trans "search" %}
</button>
<input type="text"
name="q"
class="form-control form-control-sm rounded-end"
value="{{ request.GET.q }}"
placeholder="{{ _('Enter vendor name') }}" />
{% if request.GET.q %}
<a href="{% url request.resolver_match.view_name %}"
class="btn btn-sm btn-outline-danger ms-1 rounded">
<i class="bi bi-x-lg"></i>
</a>
{% endif %}
</div>
</form>
</div> </div>
</div>
{% if page_obj.object_list %}
<div class="table-responsive scrollbar mx-n1 px-1">
<table class="table table-hover fs-9 mb-0">
<thead>
<tr>
<th class="sort white-space-nowrap align-middle text-uppercase ps-0" scope="col" data-sort="name" style="width:25%;">{{ _("Name")|capfirst }}</th>
<th class="sort align-middle ps-4 pe-5 text-uppercase border-end border-translucent" scope="col" data-sort="email" style="width:15%;">
<div class="d-inline-flex flex-center">
<div class="d-flex align-items-center px-1 py-1 bg-success-subtle rounded me-2"><span class="text-success-dark" data-feather="mail"></span></div><span>{{ _("email")|capfirst }}</span>
</div>
</th>
<th class="sort align-middle ps-4 pe-5 text-uppercase border-end border-translucent" scope="col" data-sort="phone" style="width:15%; min-width: 180px;">
<div class="d-inline-flex flex-center">
<div class="d-flex align-items-center px-1 py-1 bg-primary-subtle rounded me-2"><span class="text-primary-dark" data-feather="phone"></span></div><span>{{ _("Phone") }}</span>
</div>
</th>
<th class="sort align-middle ps-4 pe-5 text-uppercase border-end border-translucent" scope="col" data-sort="contact" style="width:15%;">
<div class="d-inline-flex flex-center">
<div class="d-flex align-items-center px-1 py-1 bg-info-subtle rounded me-2"><span class="text-info-dark" data-feather="user"></span></div><span>{{ _("Contact name")|capfirst }}</span>
</div>
</th>
<th class="sort align-middle ps-4 pe-5 text-uppercase border-end border-translucent" scope="col" data-sort="company" style="width:15%;">
<div class="d-inline-flex flex-center">
<div class="d-flex align-items-center px-1 py-1 bg-warning-subtle rounded me-2"><span class="text-warning-dark" data-feather="grid"></span></div><span>{{ _("Address")|capfirst }}</span>
</div>
</th>
<th class="sort align-middle ps-4 pe-5 text-uppercase" scope="col" data-sort="date" style="width:15%;">
{{ _("Create date") }}</th>
<th class="sort text-end align-middle pe-0 ps-4" scope="col"></th>
</tr>
</thead>
<tbody class="list" id="leal-tables-body">
{% for vendor in vendors %} {% if page_obj.object_list %}
<!-- Delete Modal --> <div class="table-responsive px-1 scrollbar mt-3">
<table class= "table align-items-center table-flush table-hover">
<tr class="hover-actions-trigger btn-reveal-trigger position-static"> <thead>
<td class="name align-middle white-space-nowrap ps-0"> <tr class="bg-body-highlight">
<div class="d-flex align-items-center"> <th class="sort white-space-nowrap align-middle" scope="col" data-sort="name" style="width:25%;">{{ _("Name")|capfirst }}</th>
{% if vendor.logo %} <th class="sort white-space-nowrap align-middle" scope="col" data-sort="email" style="width:15%;">
<div class="avatar avatar-xl me-3"><img class="rounded-circle" src="{{ vendor.logo.url }}" alt="" /> <div class="d-inline-flex flex-center">
{% else %} <div class="d-flex align-items-center px-1 py-1 bg-success-subtle rounded me-2"><span class="text-success-dark" data-feather="mail"></span></div><span>{{ _("email")|capfirst }}</span>
<div class="avatar avatar-xl me-3"><img class="rounded-circle" src="{% static 'images/icons/picture.svg' %}" alt="" /> </div>
{% endif %} </th>
<th class="sort white-space-nowrap align-middle" scope="col" data-sort="phone" style="width:15%; min-width: 180px;">
<div class="d-inline-flex flex-center">
<div class="d-flex align-items-center px-1 py-1 bg-primary-subtle rounded me-2"><span class="text-primary-dark" data-feather="phone"></span></div><span>{{ _("Phone") }}</span>
</div> </div>
<div><a class="fs-8 fw-bold" href="{% url 'vendor_detail' vendor.slug%}">{{ vendor.arabic_name }}</a> </th>
<div class="d-flex align-items-center"> <th class="sort white-space-nowrap align-middle" scope="col" data-sort="contact" style="width:15%;">
<p class="mb-0 text-body-highlight fw-semibold fs-9 me-2">{{ vendor.name}}</p><!--<span class="badge badge-phoenix badge-phoenix-primary">{{ vendor.vendor_model.uuid }}</span>--> <div class="d-inline-flex flex-center">
</div> <div class="d-flex align-items-center px-1 py-1 bg-info-subtle rounded me-2"><span class="text-info-dark" data-feather="user"></span></div><span>{{ _("Contact name")|capfirst }}</span>
</div> </div>
</div> </th>
</td> <th class="sort white-space-nowrap align-middle" scope="col" data-sort="company" style="width:15%;">
<td class="email align-middle white-space-nowrap fw-semibold ps-4 border-end border-translucent"><a class="text-body-highlight" href="">{{ vendor.email }}</a></td> <div class="d-inline-flex flex-center">
<td class="phone align-middle white-space-nowrap fw-semibold ps-4 border-end border-translucent"><a class="text-body-highlight" href="tel:{{ vendor.phone }}">{{ vendor.phone_number }}</a></td> <div class="d-flex align-items-center px-1 py-1 bg-warning-subtle rounded me-2"><span class="text-warning-dark" data-feather="grid"></span></div><span>{{ _("Address")|capfirst }}</span>
<td class="contact align-middle white-space-nowrap ps-4 border-end border-translucent fw-semibold text-body-highlight">{{ vendor.contact_person }}</td> </div>
<td class="company align-middle white-space-nowrap text-body-tertiary text-opacity-85 ps-4 border-end border-translucent fw-semibold text-body-highlight"> </th>
{{ vendor.address }}</td> <th class="sort white-space-nowrap align-middle" scope="col" data-sort="date" style="width:15%;">{{ _("Create date") }}</th>
<td class="date align-middle white-space-nowrap text-body-tertiary text-opacity-85 ps-4 text-body-tertiary">{{ vendor.created_at|date }}</td> <th class="sort white-space-nowrap align-middle" scope="col"></th>
<td class="align-middle white-space-nowrap text-end pe-0 ps-4">
<div class="btn-reveal-trigger position-static">
<button class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10" type="button" data-bs-toggle="dropdown" data-boundary="window" aria-haspopup="true" aria-expanded="false" data-bs-reference="parent"><span class="fas fa-ellipsis-h fs-10"></span></button>
<div class="dropdown-menu dropdown-menu-end py-2">
<a href="{% url 'vendor_update' vendor.slug %}" class="dropdown-item text-success-dark">
{% trans "Edit" %}
</a>
<div class="dropdown-divider"></div>
<button class="delete-btn dropdown-item text-danger"
data-url="{% url 'vendor_delete' vendor.slug %}"
data-message="{{ _("Are you sure you want to delete this vendor")}}?"
data-bs-toggle="modal" data-bs-target="#deleteModal">
{{ _("Delete") }}
</button>
</div>
</div>
</td>
</tr> </tr>
{% endfor %} </thead>
</tbody> <tbody class="list">
{% endif %} {% for vendor in vendors %}
</table>
</div> <tr class="hover-actions-trigger btn-reveal-trigger position-static">
<div class="row align-items-center justify-content-end py-4 pe-0 fs-9"> <td class="align-middle product white-space-nowrap">
<!-- Optional: Pagination --> <div class="d-flex align-items-center">
{% if is_paginated %} {% if vendor.logo %}
{% include 'partials/pagination.html' %} <div class="avatar avatar-xl me-3"><img class="rounded-circle" src="{{ vendor.logo.url }}" alt="" />
{% else %}
<div class="avatar avatar-xl me-3"><img class="rounded-circle" src="{% static 'images/icons/picture.svg' %}" alt="" />
{% endif %}
</div>
<div><a class="fs-8 fw-bold" href="{% url 'vendor_detail' vendor.slug %}">{{ vendor.arabic_name }}</a>
<div class="d-flex align-items-center">
<p class="mb-0 text-body-highlight fw-semibold fs-9 me-2">{{ vendor.name}}</p><!--<span class="badge badge-phoenix badge-phoenix-primary">{{ vendor.vendor_model.uuid }}</span>-->
</div>
</div>
</div>
</td>
<td class="align-middle product white-space-nowrap">
<a class="text-body-highlight" href="">{{ vendor.email }}</a>
</td>
<td class="align-middle product white-space-nowrap">
<a class="text-body-highlight" href="tel:{{ vendor.phone }}">{{ vendor.phone_number }}</a>
</td>
<td class="align-middle product white-space-nowrap">
{{ vendor.contact_person }}
</td>
<td class="align-middle product white-space-nowrap">
{{ vendor.address }}
</td>
<td class="align-middle product white-space-nowrap">
{{ vendor.created_at|date }}
</td>
<td class="align-middle product white-space-nowrap">
<div class="btn-reveal-trigger position-static">
<button class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10" type="button" data-bs-toggle="dropdown" data-boundary="window" aria-haspopup="true" aria-expanded="false" data-bs-reference="parent"><span class="fas fa-ellipsis-h fs-10"></span></button>
<div class="dropdown-menu dropdown-menu-end py-2">
<a href="{% url 'vendor_update' vendor.slug %}" class="dropdown-item text-success-dark">
{% trans "Edit" %}
</a>
<div class="dropdown-divider"></div>
<button class="delete-btn dropdown-item text-danger"
data-url="{% url 'vendor_delete' vendor.slug %}"
data-message="{{ _("Are you sure you want to delete this vendor")}}?"
data-bs-toggle="modal" data-bs-target="#deleteModal">
{{ _("Delete") }}
</button>
</div>
</div>
</td>
</tr>
{% empty %}
<tr>
<td colspan="6" class="text-center text-muted">{% trans "No Accounts Found" %}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="d-flex justify-content-between mt-3"><span class="d-none d-sm-inline-block" data-list-info="data-list-info">{{ page_obj.start_index }} {{ _("to") }} {{ page_obj.end_index }}<span class="text-body-tertiary"> {{ _("Items of")}} </span>{{ page_obj.paginator.count }}</span>
<div class="d-flex">
{% if is_paginated %}
{% include 'partials/pagination.html' %}
{% endif %}
</div>
</div>
{% endif %} {% endif %}
</div>
</div> </div>
</section>
{% include 'modal/delete_modal.html' %} {% include 'modal/delete_modal.html' %}
{% endblock %} {% endblock %}