Compare commits
4 Commits
589417ca6d
...
dcd30b0bb2
| Author | SHA1 | Date | |
|---|---|---|---|
| dcd30b0bb2 | |||
| ce644d9d33 | |||
| caae2925bf | |||
| 870bcfdcec |
@ -144,11 +144,10 @@ class StaffForm(forms.ModelForm):
|
||||
queryset=CustomGroup.objects.all(),
|
||||
required=True,
|
||||
)
|
||||
name = forms.CharField(
|
||||
label=_("Full Name"))
|
||||
|
||||
class Meta:
|
||||
model = Staff
|
||||
fields = ["first_name","last_name","name", "arabic_name", "phone_number", "address", "logo", "group"]
|
||||
fields = ["first_name","last_name", "arabic_name", "phone_number", "address", "logo", "group"]
|
||||
|
||||
|
||||
# Dealer Form
|
||||
|
||||
@ -594,7 +594,7 @@ class AdditionalServices(models.Model, LocalizedNameMixin):
|
||||
if self.taxable
|
||||
else self.price
|
||||
)
|
||||
|
||||
|
||||
@property
|
||||
def service_tax(self):
|
||||
vat = VatRate.objects.filter(dealer=self.dealer, is_active=True).first()
|
||||
@ -896,18 +896,18 @@ class Car(Base):
|
||||
def vat_amount(self):
|
||||
vat = VatRate.objects.filter(dealer=self.dealer,is_active=True).first()
|
||||
return Decimal(self.final_price) * (vat.rate)
|
||||
|
||||
|
||||
@property
|
||||
def total_services_and_car_vat(self):
|
||||
return self.vat_amount+self.get_additional_services()['services_vat']
|
||||
|
||||
|
||||
@property
|
||||
def final_price_plus_vat(self):
|
||||
return Decimal(self.final_price) + Decimal(self.vat_amount)
|
||||
|
||||
|
||||
@property
|
||||
def final_price_plus_services_plus_vat(self):
|
||||
return Decimal(self.final_price_plus_vat) + Decimal(self.get_additional_services()['total_']) #total services with vat and car_sell price with vat
|
||||
return Decimal(self.final_price_plus_vat) + Decimal(self.get_additional_services()['total_']) #total services with vat and car_sell price with vat
|
||||
# to be used after invoice is created
|
||||
@property
|
||||
def invoice(self):
|
||||
@ -929,8 +929,8 @@ class Car(Base):
|
||||
except ExtraInfo.DoesNotExist:
|
||||
return Decimal(0)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# def get_discount_amount(self,estimate,user):
|
||||
# try:
|
||||
# instance = models.ExtraInfo.objects.get(
|
||||
@ -1419,7 +1419,7 @@ class StaffTypes(models.TextChoices):
|
||||
# AGENT = "agent", _("Agent")
|
||||
|
||||
|
||||
class Staff(models.Model, LocalizedNameMixin):
|
||||
class Staff(models.Model):
|
||||
# staff_member = models.OneToOneField(
|
||||
# StaffMember, on_delete=models.CASCADE, related_name="staff"
|
||||
# )
|
||||
@ -1429,7 +1429,7 @@ class Staff(models.Model, LocalizedNameMixin):
|
||||
dealer = models.ForeignKey(Dealer, on_delete=models.CASCADE, related_name="staff")
|
||||
first_name = models.CharField(max_length=255, verbose_name=_("First Name"))
|
||||
last_name = models.CharField(max_length=255, verbose_name=_("Last Name"))
|
||||
name = models.CharField(max_length=255, verbose_name=_("Name"))
|
||||
|
||||
arabic_name = models.CharField(max_length=255, verbose_name=_("Arabic Name"))
|
||||
phone_number = PhoneNumberField(region="SA", verbose_name=_("Phone Number"))
|
||||
staff_type = models.CharField(
|
||||
@ -1456,7 +1456,7 @@ class Staff(models.Model, LocalizedNameMixin):
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.slug:
|
||||
base_slug = slugify(f"{self.name}")
|
||||
base_slug = slugify(f"{self.first_name}-{self.last_name}")
|
||||
self.slug = base_slug
|
||||
counter = 1
|
||||
|
||||
@ -1471,6 +1471,9 @@ class Staff(models.Model, LocalizedNameMixin):
|
||||
|
||||
objects = StaffUserManager()
|
||||
|
||||
@property
|
||||
def fullname(self):
|
||||
return self.first_name + " " + self.last_name
|
||||
def deactivate_account(self):
|
||||
self.active = False
|
||||
self.user.is_active = False
|
||||
@ -1530,7 +1533,6 @@ class Staff(models.Model, LocalizedNameMixin):
|
||||
verbose_name = _("Staff")
|
||||
verbose_name_plural = _("Staff")
|
||||
indexes = [
|
||||
models.Index(fields=["name"]),
|
||||
models.Index(fields=["staff_type"]),
|
||||
]
|
||||
permissions = []
|
||||
@ -1542,7 +1544,7 @@ class Staff(models.Model, LocalizedNameMixin):
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.name}"
|
||||
return f"{self.first_name} {self.last_name}"
|
||||
|
||||
|
||||
class Sources(models.TextChoices):
|
||||
|
||||
@ -458,7 +458,7 @@ def general_dashboard(request,dealer_slug):
|
||||
total_vat_collected_from_cars = cars_sold_filtered.aggregate(
|
||||
total=Sum(F('selling_price') * VAT_RATE)
|
||||
)['total'] or 0
|
||||
|
||||
|
||||
net_profit_from_cars = total_revenue_from_cars - total_cost_of_cars_sold
|
||||
total_discount = cars_sold_filtered.aggregate(total=Sum('discount_amount'))['total'] or 0
|
||||
|
||||
@ -519,7 +519,7 @@ def general_dashboard(request,dealer_slug):
|
||||
monthly_cars_sold_json = json.dumps(monthly_cars_sold)
|
||||
monthly_revenue_json = json.dumps(monthly_revenue)
|
||||
monthly_net_profit_json = json.dumps(monthly_net_profit)
|
||||
|
||||
|
||||
# ----------------------------------------------------
|
||||
# Sales by MAKE
|
||||
# ----------------------------------------------------
|
||||
@ -529,9 +529,9 @@ def general_dashboard(request,dealer_slug):
|
||||
|
||||
sales_by_make_labels = [data['id_car_make__name'] for data in sales_by_make_data]
|
||||
sales_by_make_counts = [data['car_count'] for data in sales_by_make_data]
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# ----------------------------------------------------
|
||||
# DATA FOR CAR SALES BY MODELS (for the new interactive chart)
|
||||
# ----------------------------------------------------
|
||||
@ -555,15 +555,15 @@ def general_dashboard(request,dealer_slug):
|
||||
# If no make is selected, pass an empty list or some default data
|
||||
sales_data_by_model = []
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# 1. Inventory by Make (Pie Chart)
|
||||
|
||||
inventory_by_make_data = active_cars.values('id_car_make__name').annotate(
|
||||
car_count=Count('id_car_make__name')
|
||||
).order_by('-car_count')
|
||||
|
||||
|
||||
inventory_by_make_labels = [data['id_car_make__name'] for data in inventory_by_make_data]
|
||||
inventory_by_make_counts = [data['car_count'] for data in inventory_by_make_data]
|
||||
|
||||
@ -582,7 +582,7 @@ def general_dashboard(request,dealer_slug):
|
||||
else:
|
||||
# Default data
|
||||
inventory_data_by_model = []
|
||||
|
||||
|
||||
context = {
|
||||
'start_date': start_date,
|
||||
'end_date': end_date,
|
||||
@ -631,14 +631,14 @@ def general_dashboard(request,dealer_slug):
|
||||
'monthly_revenue_json': monthly_revenue_json,
|
||||
'monthly_net_profit_json': monthly_net_profit_json,
|
||||
|
||||
|
||||
|
||||
# Sales Chart Data
|
||||
'sales_by_make_labels_json': json.dumps(sales_by_make_labels),
|
||||
'sales_by_make_counts_json': json.dumps(sales_by_make_counts),
|
||||
'all_makes_sold': all_makes_sold,
|
||||
'selected_make_sales': selected_make_sales,
|
||||
'sales_data_by_model_json': json.dumps(list(sales_data_by_model)),
|
||||
|
||||
|
||||
# New Inventory Chart Data
|
||||
'inventory_by_make_labels_json': json.dumps(inventory_by_make_labels),
|
||||
'inventory_by_make_counts_json': json.dumps(inventory_by_make_counts),
|
||||
@ -646,9 +646,9 @@ def general_dashboard(request,dealer_slug):
|
||||
'selected_make_inventory': selected_make_inventory,
|
||||
'inventory_data_by_model_json': json.dumps(list(inventory_data_by_model)),
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
return render(request, 'dashboards/general_dashboard.html', context)
|
||||
|
||||
@ -670,7 +670,7 @@ def sales_dashboard(request,dealer_slug):
|
||||
else:
|
||||
start_date = today_local - timedelta(days=30)
|
||||
end_date = today_local
|
||||
|
||||
|
||||
# Filter leads by date range and dealer
|
||||
leads_filtered = models.Lead.objects.filter(
|
||||
dealer=dealer,
|
||||
@ -678,7 +678,7 @@ def sales_dashboard(request,dealer_slug):
|
||||
created__date__lte=end_date
|
||||
)
|
||||
|
||||
|
||||
|
||||
# ----------------------------------------------------
|
||||
# 2. Lead Sources Chart Logic
|
||||
# ----------------------------------------------------
|
||||
@ -748,7 +748,7 @@ def aging_inventory_list_view(request, dealer_slug):
|
||||
dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
|
||||
today_local = timezone.localdate()
|
||||
aging_threshold_days = 60
|
||||
|
||||
|
||||
# Get filter parameters from the request
|
||||
selected_make = request.GET.get('make')
|
||||
selected_model = request.GET.get('model')
|
||||
@ -762,7 +762,7 @@ def aging_inventory_list_view(request, dealer_slug):
|
||||
receiving_date__date__lt=today_local - timedelta(days=aging_threshold_days)
|
||||
).exclude(status='sold')
|
||||
total_aging_inventory_value=aging_cars_queryset.aggregate(total=Sum('cost_price'))['total']
|
||||
|
||||
|
||||
# Apply filters to the queryset if they exist. Chaining is fine here.
|
||||
if selected_make:
|
||||
aging_cars_queryset = aging_cars_queryset.filter(id_car_make__name=selected_make)
|
||||
@ -774,7 +774,7 @@ def aging_inventory_list_view(request, dealer_slug):
|
||||
aging_cars_queryset = aging_cars_queryset.filter(id_car_year__year=selected_year)
|
||||
if selected_stock_type:
|
||||
aging_cars_queryset = aging_cars_queryset.filter(stock_type=selected_stock_type)
|
||||
|
||||
|
||||
|
||||
# Get distinct values for filter dropdowns based on the initial, unfiltered aging cars queryset.
|
||||
# This ensures all possible filter options are always available.
|
||||
@ -782,19 +782,19 @@ def aging_inventory_list_view(request, dealer_slug):
|
||||
dealer=dealer,
|
||||
receiving_date__date__lt=today_local - timedelta(days=aging_threshold_days)
|
||||
).exclude(status='sold')
|
||||
|
||||
|
||||
all_makes = aging_base_queryset.values_list('id_car_make__name', flat=True).distinct().order_by('id_car_make__name')
|
||||
all_models = aging_base_queryset.values_list('id_car_model__name', flat=True).distinct().order_by('id_car_model__name')
|
||||
all_series = aging_base_queryset.values_list('id_car_serie__name', flat=True).distinct().order_by('id_car_serie__name')
|
||||
all_stock_types = aging_base_queryset.values_list('stock_type', flat=True).distinct().order_by('stock_type')
|
||||
all_years = aging_base_queryset.values_list('year', flat=True).distinct().order_by('-year')
|
||||
|
||||
|
||||
#
|
||||
# Set up pagination
|
||||
paginator = Paginator(aging_cars_queryset, 10)
|
||||
page_number = request.GET.get('page')
|
||||
page_obj = paginator.get_page(page_number)
|
||||
|
||||
|
||||
# Iterate only on the cars for the current page to add the age attribute.
|
||||
for car in page_obj.object_list:
|
||||
car.age_in_days = (today_local - car.receiving_date.date()).days
|
||||
@ -803,7 +803,7 @@ def aging_inventory_list_view(request, dealer_slug):
|
||||
"is_paginated": page_obj.has_other_pages,
|
||||
"cars": page_obj.object_list,
|
||||
'selected_make': selected_make,
|
||||
'selected_model': selected_model,
|
||||
'selected_model': selected_model,
|
||||
'selected_series': selected_series, # Corrected variable name
|
||||
'selected_year': selected_year,
|
||||
'selected_stock_type': selected_stock_type,
|
||||
@ -813,9 +813,9 @@ def aging_inventory_list_view(request, dealer_slug):
|
||||
'all_stock_types': all_stock_types,
|
||||
'all_years': all_years,
|
||||
'total_aging_inventory_value':total_aging_inventory_value
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
return render(request, 'dashboards/aging_inventory_list.html', context)
|
||||
|
||||
def terms_and_privacy(request):
|
||||
@ -2813,12 +2813,15 @@ def vendorDetailView(request, dealer_slug, slug):
|
||||
"""
|
||||
dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
|
||||
vendor = get_object_or_404(models.Vendor, slug=slug,dealer=dealer)
|
||||
cars=vendor.cars.all()
|
||||
total_cars_from_vendor=cars.count()
|
||||
vendor_makes=cars.values('id_car_make__name').annotate(make_count=Count('id_car_make__name'))
|
||||
vendor_bills=BillModel.objects.filter(vendor=vendor.vendor_model)
|
||||
paginator=Paginator(vendor_bills,20)
|
||||
page_number = request.GET.get("page")
|
||||
page_obj=paginator.get_page(page_number)
|
||||
return render(
|
||||
request, template_name="vendors/view_vendor.html", context={"vendor": vendor,"vendor_bills":page_obj}
|
||||
request, template_name="vendors/view_vendor.html", context={"vendor": vendor,"vendor_bills":page_obj,"total_cars_from_vendor":total_cars_from_vendor,"vendor_makes":vendor_makes}
|
||||
)
|
||||
|
||||
|
||||
@ -3720,7 +3723,7 @@ class UserUpdateView(
|
||||
|
||||
staff = form.save(commit=False)
|
||||
print(form.cleaned_data)
|
||||
staff.name = form.cleaned_data["name"]
|
||||
# staff.name = form.cleaned_data["name"]
|
||||
staff.arabic_name = form.cleaned_data["arabic_name"]
|
||||
staff.phone_number = form.cleaned_data["phone_number"]
|
||||
for customgroup in form.cleaned_data["group"]:
|
||||
@ -5027,7 +5030,7 @@ class EstimateDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView
|
||||
# calculator = CarFinanceCalculator(estimate)
|
||||
# finance_data = calculator.get_finance_data()
|
||||
finance_data = get_finance_data(estimate,dealer)
|
||||
|
||||
|
||||
invoice_obj = InvoiceModel.objects.all().filter(ce_model=estimate).first()
|
||||
kwargs["data"] = finance_data
|
||||
|
||||
@ -5036,7 +5039,7 @@ class EstimateDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView
|
||||
car = estimate.get_itemtxs_data()[0].first().item_model.car
|
||||
selected_items = car.additional_services.filter(dealer=dealer)
|
||||
form = forms.AdditionalFinancesForm()
|
||||
form.fields["additional_finances"].queryset = form.fields["additional_finances"].queryset.filter(dealer=dealer) #
|
||||
form.fields["additional_finances"].queryset = form.fields["additional_finances"].queryset.filter(dealer=dealer) #
|
||||
form.initial["additional_finances"] = selected_items
|
||||
kwargs["additionals_form"] = form
|
||||
except Exception as e:
|
||||
@ -7046,7 +7049,7 @@ def send_lead_email(request, dealer_slug, slug, email_pk=None):
|
||||
تحياتي،
|
||||
{lead.dealer.arabic_name}
|
||||
{lead.dealer.address}
|
||||
{lead.dealer.phone_number}
|
||||
{lead.dealer.phone_number}
|
||||
-----
|
||||
Dear {lead.full_name},
|
||||
|
||||
@ -11065,7 +11068,7 @@ def purchase_report_csv_export(request,dealer_slug):
|
||||
def car_sale_report_view(request, dealer_slug):
|
||||
dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
|
||||
cars_sold = models.Car.objects.filter(dealer=dealer, status='sold')
|
||||
|
||||
|
||||
|
||||
# Get filter parameters from the request
|
||||
selected_make = request.GET.get('make')
|
||||
@ -11089,8 +11092,8 @@ def car_sale_report_view(request, dealer_slug):
|
||||
|
||||
# # Calculate summary data for the filtered results
|
||||
total_cars_sold=cars_sold.count()
|
||||
total_revenue_from_cars = sum([ car.final_price for car in cars_sold])
|
||||
total_vat_on_cars=sum([car.vat_amount for car in cars_sold])
|
||||
total_revenue_from_cars = sum([ car.final_price for car in cars_sold])
|
||||
total_vat_on_cars=sum([car.vat_amount for car in cars_sold])
|
||||
|
||||
total_revenue_from_additonals=sum([car.get_additional_services()['total'] for car in cars_sold])
|
||||
total_vat_from_additonals=sum([car.get_additional_services()['services_vat'] for car in cars_sold])
|
||||
@ -11104,11 +11107,11 @@ def car_sale_report_view(request, dealer_slug):
|
||||
base_sold_cars_queryset = models.Car.objects.filter(dealer=dealer, status='sold')
|
||||
makes =base_sold_cars_queryset.values_list('id_car_make__name', flat=True).distinct()
|
||||
models_qs =base_sold_cars_queryset.values_list('id_car_model__name', flat=True).distinct()
|
||||
|
||||
|
||||
series =base_sold_cars_queryset.values_list('id_car_serie__name', flat=True).distinct()
|
||||
stock_types=base_sold_cars_queryset.values_list('stock_type', flat=True).distinct()
|
||||
years = base_sold_cars_queryset.values_list('year', flat=True).distinct().order_by('-year')
|
||||
|
||||
|
||||
context = {
|
||||
'cars_sold': cars_sold,
|
||||
'total_cars_sold':total_cars_sold,
|
||||
@ -11182,7 +11185,7 @@ def car_sale_report_csv_export(request, dealer_slug):
|
||||
additional_services = car.get_additional_services()
|
||||
services_total_price = additional_services['total']
|
||||
services_vat_amount = additional_services['services_vat']
|
||||
|
||||
|
||||
# Checking for the invoice number to avoid errors on cars without one
|
||||
invoice_number = None
|
||||
sold_date = None
|
||||
|
||||
@ -20,8 +20,12 @@
|
||||
|
||||
<h6 class="text-uppercase text-xs text-muted mb-2">
|
||||
{% trans 'Cash Account' %}:
|
||||
<a href="{% url 'account_detail' request.dealer.slug bill.cash_account.uuid %}"
|
||||
{% if bill.cash_account %}
|
||||
<a href="{% url 'account_detail' request.dealer.slug bill.cash_account.coa_model.pk bill.cash_account.uuid %}"
|
||||
class="text-decoration-none ms-1">{{ bill.cash_account.code }}</a>
|
||||
{% else %}
|
||||
{{ bill.cash_account.code }}
|
||||
{% endif %}
|
||||
</h6>
|
||||
<h4 class="mb-0" id="djl-bill-detail-amount-paid">
|
||||
{% currency_symbol %}{{ bill.get_amount_cash | absolute | currency_format }}
|
||||
@ -33,10 +37,14 @@
|
||||
|
||||
<h6 class="text-uppercase text-xs text-muted mb-2">
|
||||
{% trans 'Prepaid Account' %}:
|
||||
<a href="{% url 'account_detail' request.dealer.slug bill.prepaid_account.uuid %}"
|
||||
{% if bill.prepaid_account %}
|
||||
<a href="{% url 'account_detail' request.dealer.slug bill.prepaid_account.coa_model.pk bill.prepaid_account.uuid %}"
|
||||
class="text-decoration-none ms-1">
|
||||
{{ bill.prepaid_account.code }}
|
||||
</a>
|
||||
{% else %}
|
||||
{{ bill.prepaid_account.code }}
|
||||
{% endif %}
|
||||
</h6>
|
||||
<h4 class="text-success mb-0" id="djl-bill-detail-amount-prepaid">
|
||||
{% currency_symbol %}{{ bill.get_amount_prepaid | currency_format }}
|
||||
@ -47,10 +55,14 @@
|
||||
|
||||
<h6 class="text-uppercase text-xs text-muted mb-2">
|
||||
{% trans 'Accounts Payable' %}:
|
||||
<a href="{% url 'account_detail' request.dealer.slug bill.unearned_account.uuid %}"
|
||||
class="text-decoration-none ms-1">
|
||||
{{ bill.unearned_account.code }}
|
||||
</a>
|
||||
{% if bill.unearned_account %}
|
||||
<a href="{% url 'account_detail' request.dealer.slug bill.unearned_account.coa_model.pk bill.unearned_account.uuid %}"
|
||||
class="text-decoration-none ms-1">
|
||||
{{ bill.unearned_account.code }}
|
||||
</a>
|
||||
{% else %}
|
||||
{{ bill.unearned_account.code }}
|
||||
{% endif %}
|
||||
</h6>
|
||||
<h4 class="text-danger mb-0" id="djl-bill-detail-amount-unearned">
|
||||
{% currency_symbol %}{{ bill.get_amount_unearned | currency_format }}
|
||||
|
||||
@ -39,9 +39,9 @@
|
||||
</div>
|
||||
|
||||
|
||||
<div class="d-grid gap-2 mt-4">
|
||||
<button type="submit" class="btn btn-primary btn-lg">Submit</button>
|
||||
<a href="{% url 'coa-list' request.dealer.slug request.entity.slug %}" class="btn btn-outline-dark">
|
||||
<div class="d-flex justify-content-center gap-2 mt-4">
|
||||
<button type="submit" class="btn btn-phoenix-primary">Submit</button>
|
||||
<a href="{% url 'coa-list' request.dealer.slug request.entity.slug %}" class="btn btn-phoenix-secondary">
|
||||
{% trans 'Back' %}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@ -9,18 +9,18 @@
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h1 class="display-4 mb-0">Chart of Accounts</h1>
|
||||
<a href="{% url 'coa-create' request.dealer.slug request.entity.slug %}" class="btn btn-success btn-lg">
|
||||
{% icon 'carbon:add-alt' 24 %} Add New
|
||||
<h1 class="display-4 mb-0">{% trans "Chart of Accounts" %}</h1>
|
||||
<a href="{% url 'coa-create' request.dealer.slug request.entity.slug %}" class="btn btn-phoenix-primary">
|
||||
<i class="fa-solid fa-plus"></i> {% trans "Add New" %}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{% if not inactive %}
|
||||
<a class="btn btn-warning mb-4" href="{% url 'coa-list-inactive' request.dealer.slug request.entity.slug %}">
|
||||
<a class="btn btn-phoenix-warning mb-4" href="{% url 'coa-list-inactive' request.dealer.slug request.entity.slug %}">
|
||||
{% trans 'Show Inactive' %}
|
||||
</a>
|
||||
{% else %}
|
||||
<a class="btn btn-warning mb-4" href="{% url 'coa-list' request.dealer.slug request.entity.slug %}">
|
||||
<a class="btn btn-phoenix-warning mb-4" href="{% url 'coa-list' request.dealer.slug request.entity.slug %}">
|
||||
{% trans 'Show Active' %}
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
@ -32,13 +32,13 @@
|
||||
</div>
|
||||
|
||||
|
||||
<div class="d-grid gap-2 mt-4">
|
||||
<button class="btn btn-primary" type="submit">
|
||||
Update
|
||||
<div class="d-flex justify-content-center gap-2 mt-4">
|
||||
<button class="btn btn-phoenix-primary" type="submit">
|
||||
{% trans 'Update'%}
|
||||
</button>
|
||||
<a class="btn btn-outline-secondary"
|
||||
<a class="btn btn-phoenix-secondary"
|
||||
href="{% url 'coa-list' request.dealer.slug request.entity.slug %}">
|
||||
Back
|
||||
{% trans 'Back'%}
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@ -3,33 +3,37 @@
|
||||
{% now "Y" as current_year %}
|
||||
|
||||
<div class="card shadow-sm border-0 mb-4">
|
||||
<div class="card-header {% if coa_model.is_default %}bg-success text-white{% elif not coa_model.is_active %}bg-danger text-white{% endif %} py-3">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="me-3">
|
||||
<i class="fas fa-building fa-2x"></i>
|
||||
</div>
|
||||
<div class="fw-bold fs-5">
|
||||
<div class="card-header {% if coa_model.is_default %}bg-gray-100{% elif not coa_model.is_active %}bg-danger text-white{% endif %} py-3 d-flex align-items-center">
|
||||
<div class="me-3">
|
||||
<i class="fas fa-building fa-2x"></i>
|
||||
</div>
|
||||
<div class="flex-grow-1">
|
||||
<h5 class="fw-bold mb-0">
|
||||
{{ coa_model.name }}
|
||||
{% if coa_model.is_default %}
|
||||
<span class="badge bg-light text-dark ms-2">{% trans 'DEFAULT' %}</span>
|
||||
<span class="badge bg-light text-primary ms-2 d-none d-sm-inline">{% trans 'DEFAULT' %}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</h5>
|
||||
{% if coa_model.is_default %}
|
||||
<span class="badge bg-light text-primary mt-1 d-sm-none">{% trans 'DEFAULT' %}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="ms-auto d-flex flex-column align-items-end">
|
||||
{% if coa_model.is_active %}
|
||||
<span class="badge bg-success"><i class="fas fa-check-circle"></i> {% trans 'Active' %}</span>
|
||||
{% else %}
|
||||
<span class="badge bg-danger"><i class="fas fa-times-circle"></i> {% trans 'Inactive' %}</span>
|
||||
{% endif %}
|
||||
{% if coa_model.is_default %}
|
||||
<span class="badge bg-primary-subtle text-primary mt-1">{% trans 'Entity Default' %}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body">
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<span class="fw-bold me-2">{% trans 'Entity Default' %}:</span>
|
||||
{% if coa_model.is_default %}
|
||||
<span class="badge bg-success"><i class="fas fa-check-circle"></i></span>
|
||||
{% else %}
|
||||
<span class="badge bg-danger"><i class="fas fa-times-circle"></i></span>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<div class="col-sm-6">
|
||||
<div class="d-flex flex-wrap align-items-center mb-2">
|
||||
<span class="fw-bold me-2">{% trans 'Is Active' %}:</span>
|
||||
{% if coa_model.is_active %}
|
||||
<span class="badge bg-success"><i class="fas fa-check-circle"></i></span>
|
||||
@ -37,14 +41,13 @@
|
||||
<span class="badge bg-danger"><i class="fas fa-times-circle"></i></span>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="mb-2">
|
||||
<span class="fw-bold">CoA ID:</span>
|
||||
<span class="text-muted ms-2">{{ coa_model.slug }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="col-sm-6">
|
||||
<div class="mb-2">
|
||||
<span class="fw-bold"><i class="fas fa-list-alt me-1"></i> {% trans 'Total Accounts' %}:</span>
|
||||
<span class="ms-2">{{ coa_model.accountmodel_total__count }}</span>
|
||||
@ -64,50 +67,50 @@
|
||||
|
||||
<hr class="my-3">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<small class="text-muted">
|
||||
<div class="row g-2">
|
||||
<div class="col-sm-6">
|
||||
<small class="text-muted d-block">
|
||||
<i class="far fa-calendar-plus me-1"></i>
|
||||
<span class="fw-bold">{% trans 'Created' %}:</span>
|
||||
{{ coa_model.created|date }}
|
||||
<span class="d-block d-md-inline-block">{{ coa_model.created|date }}</span>
|
||||
</small>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<small class="text-muted">
|
||||
<div class="col-sm-6">
|
||||
<small class="text-muted d-block">
|
||||
<i class="far fa-clock me-1"></i>
|
||||
<span class="fw-bold">{% trans 'Updated' %}:</span>
|
||||
{{ coa_model.created|timesince }} {% trans 'ago' %}
|
||||
<span class="d-block d-md-inline-block">{{ coa_model.created|timesince }} {% trans 'ago' %}</span>
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-footer bg-transparent border-top-0">
|
||||
<div class="card-footer bg-transparent border-top-0 pt-0 pt-sm-3">
|
||||
<div class="d-flex flex-wrap gap-2">
|
||||
<a href="{% url 'coa-update' request.dealer.slug request.entity.slug coa_model.slug %}" class="btn btn-sm btn-outline-warning fw-bold">
|
||||
<a href="{% url 'coa-update' request.dealer.slug request.entity.slug coa_model.slug %}" class="btn btn-sm btn-phoenix-warning fw-bold flex-grow-1 flex-sm-grow-0">
|
||||
<i class="fas fa-edit me-1"></i> {% trans 'Update' %}
|
||||
</a>
|
||||
|
||||
<a href="{% url 'account_list' request.dealer.slug coa_model.pk %}" class="btn btn-sm btn-outline-success fw-bold">
|
||||
<a href="{% url 'account_list' request.dealer.slug coa_model.pk %}" class="btn btn-sm btn-phoenix-success fw-bold flex-grow-1 flex-sm-grow-0">
|
||||
<i class="fas fa-book me-1"></i> {% trans 'Accounts' %}
|
||||
</a>
|
||||
|
||||
<a href="{% url 'account_create' request.dealer.slug coa_model.pk %}" class="btn btn-sm btn-outline-info fw-bold">
|
||||
<a href="{% url 'account_create' request.dealer.slug coa_model.pk %}" class="btn btn-sm btn-phoenix-info fw-bold flex-grow-1 flex-sm-grow-0">
|
||||
<i class="fas fa-plus-circle me-1"></i> {% trans 'Add Account' %}
|
||||
</a>
|
||||
|
||||
{% if coa_model.can_mark_as_default %}
|
||||
<a href="{% url 'coa-action-mark-as-default' request.dealer.slug request.entity.slug coa_model.slug %}" class="btn btn-sm btn-outline-danger fw-bold">
|
||||
<a href="{% url 'coa-action-mark-as-default' request.dealer.slug request.entity.slug coa_model.slug %}" class="btn btn-sm btn-phoenix-danger fw-bold flex-grow-1 flex-sm-grow-0">
|
||||
<i class="fas fa-star me-1"></i> {% trans 'Mark as Default' %}
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
{% if coa_model.can_deactivate %}
|
||||
<a href="{% url 'coa-action-mark-as-inactive' request.dealer.slug request.entity.slug coa_model.slug %}" class="btn btn-sm btn-outline-warning fw-bold">
|
||||
<a href="{% url 'coa-action-mark-as-inactive' request.dealer.slug request.entity.slug coa_model.slug %}" class="btn btn-sm btn-phoenix-warning fw-bold flex-grow-1 flex-sm-grow-0">
|
||||
<i class="fas fa-toggle-off me-1"></i> {% trans 'Mark as Inactive' %}
|
||||
</a>
|
||||
{% elif coa_model.can_activate %}
|
||||
<a href="{% url 'coa-action-mark-as-active' request.dealer.slug request.entity.slug coa_model.slug %}" class="btn btn-sm btn-outline-success fw-bold">
|
||||
<a href="{% url 'coa-action-mark-as-active' request.dealer.slug request.entity.slug coa_model.slug %}" class="btn btn-sm btn-phoenix-success fw-bold flex-grow-1 flex-sm-grow-0">
|
||||
<i class="fas fa-toggle-on me-1"></i> {% trans 'Mark as Active' %}
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
@ -109,7 +109,7 @@
|
||||
{% if lead.staff == request.staff %}
|
||||
{{ _("Me") }}
|
||||
{% elif LANGUAGE_CODE == "en" %}
|
||||
{{ lead.staff.name|capfirst }}
|
||||
{{ lead.staff.fullname|capfirst }}
|
||||
{% else %}
|
||||
{{ lead.staff.arabic_name }}
|
||||
{% endif %}
|
||||
|
||||
@ -199,7 +199,7 @@
|
||||
{% if lead.staff == request.staff %}
|
||||
{{ _("Me") }}
|
||||
{% elif LANGUAGE_CODE == "en" %}
|
||||
{{ lead.staff.name|capfirst }}
|
||||
{{ lead.staff.fullname|capfirst }}
|
||||
{% else %}
|
||||
{{ lead.staff.arabic_name }}
|
||||
{% endif %}
|
||||
|
||||
@ -84,7 +84,7 @@
|
||||
</div>
|
||||
<div class="d-flex align-items-center">
|
||||
<span class="uil uil-headphones me-2"></span>
|
||||
<p class="text-body-secondary fw-bold fs-10 mb-0">{{ opportunity.staff.name }}</p>
|
||||
<p class="text-body-secondary fw-bold fs-10 mb-0">{{ opportunity.staff.fullname }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="collapse" id="collapseWidthDeals-1">
|
||||
|
||||
@ -75,7 +75,7 @@
|
||||
{% if request.user.email == opportunity.staff.email %}
|
||||
{{ _("You") }}
|
||||
{% else %}
|
||||
{{ opportunity.staff.name }}
|
||||
{{ opportunity.staff.fullname }}
|
||||
</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
@ -73,9 +73,9 @@
|
||||
<td class="text-center">
|
||||
{% if f.instance.bill_model %}
|
||||
{% if f.instance.bill_model.is_paid %}
|
||||
<span class="text-success">{% icon 'bi:check-circle-fill' 24 %}</span>
|
||||
<span class="text-success">{% trans 'Yes' %}</span>
|
||||
{% else %}
|
||||
<span class="text-danger">{% icon 'clarity:no-access-solid' 24 %}</span>
|
||||
<span class="text-danger">{% trans 'No' %}</span>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</td>
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<a href="{% url 'staff_password_reset' request.dealer.slug staff.pk %}"
|
||||
class="btn btn-phoenix-primary btn-lg shadow-sm">
|
||||
class="btn btn-phoenix-danger btn-lg shadow-sm">
|
||||
<i class="fas fa-key me-2"></i>{{ _("Change Password") }}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@ -5,11 +5,12 @@
|
||||
{{ user_.name }}
|
||||
{% endblock title %}
|
||||
{% block content %}
|
||||
|
||||
<div class="container py-4">
|
||||
<div class="d-flex flex-wrap justify-content-between align-items-center mb-4">
|
||||
<div class="d-flex align-items-center mb-3 mb-md-0">
|
||||
<a href="{% url 'user_list' request.dealer.slug %}" class="btn btn-phoenix-secondary btn-sm me-3">
|
||||
<i class="fa-regular fa-circle-left me-2"></i>{% trans "Back to Staff" %}
|
||||
<i class="fa-regular fa-circle-left me-2"></i>{% trans "Back to Staffs" %}
|
||||
</a>
|
||||
<h1 class="h4 fw-bold mb-0">{% trans "Staff Profile" %}</h1>
|
||||
</div>
|
||||
@ -22,6 +23,10 @@
|
||||
data-bs-toggle="modal" data-bs-target="#deleteModal">
|
||||
<i class="fas fa-trash-alt me-2"></i>{% trans "Delete" %}
|
||||
</button>
|
||||
<a href="{% url 'staff_password_reset' request.dealer.slug user_.pk %}"
|
||||
class="btn btn-phoenix-danger">
|
||||
<i class="fas fa-key me-2"></i>{{ _("Change Password") }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -32,12 +37,12 @@
|
||||
<div class="position-relative d-inline-block mb-3">
|
||||
{% if user_.logo %}
|
||||
<img class="rounded-circle border border-4 border-body-tertiary"
|
||||
src="{{ user_.logo.url }}" alt="{{ user_.name }}"
|
||||
src="{{ user_.logo.url }}" alt="{{ user_.fullname }}"
|
||||
style="object-fit: cover; width: 120px; height: 120px;">
|
||||
{% else %}
|
||||
<div class="rounded-circle d-inline-flex align-items-center justify-content-center bg-primary text-white border border-4 border-body-tertiary"
|
||||
style="width: 120px; height: 120px; font-size: 3rem;">
|
||||
{{ user_.name|first|upper }}
|
||||
{{ user_.fullname|first|upper }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
@ -32,7 +32,6 @@
|
||||
{{ redirect_field }}
|
||||
{{ form.first_name|as_crispy_field }}
|
||||
{{ form.last_name|as_crispy_field }}
|
||||
{{ form.name|as_crispy_field }}
|
||||
{{ form.arabic_name|as_crispy_field }}
|
||||
{{ form.email|as_crispy_field }}
|
||||
{{ form.phone_number|as_crispy_field }}
|
||||
|
||||
@ -49,16 +49,16 @@
|
||||
<img class="avatar-img rounded-circle"
|
||||
src="{{ user.thumbnail.url }}"
|
||||
onerror="this.src='/static/user-logo.jpg'"
|
||||
alt="{{ user.name }}'s logo">
|
||||
alt="{{ user.fullname }}'s logo">
|
||||
{% else %}
|
||||
<div class="rounded-circle bg-light d-flex justify-content-center align-items-center text-secondary" style="width: 2.5rem; height: 2.5rem; font-size: 1rem;">
|
||||
{{ user.name|first|upper }}
|
||||
{{ user.fullname|first|upper }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<a class="fw-bold text-decoration-none text-dark"
|
||||
href="{% url 'user_detail' request.dealer.slug user.slug %}">
|
||||
{{ user.name }}
|
||||
{{ user.fullname }}
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
46
templates/vendors/view_vendor.html
vendored
46
templates/vendors/view_vendor.html
vendored
@ -3,14 +3,17 @@
|
||||
{% block title %}
|
||||
{% trans "View Vendor" %}
|
||||
{% endblock title %}
|
||||
{% block customCSS %}
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
|
||||
<!-- Vendor Details -->
|
||||
<div class="row mt-4">
|
||||
<div class="card shadow rounded">
|
||||
<p class="card-header mb-0 fs-5">{% trans "Vendor Details" %}</p>
|
||||
<div class="card-body">
|
||||
<div class="row justify-content-start">
|
||||
<div class="col-6 col-sm-auto mb-sm-2">
|
||||
<div class="col-md-4 col-sm-auto mb-sm-2">
|
||||
<div class="avatar avatar-5xl">
|
||||
{% if vendor.logo%}<img class="rounded-circle" src="{{ vendor.logo.url }}" alt="" />{% endif %}
|
||||
</div>
|
||||
@ -37,7 +40,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-6 col-sm-auto mb-sm-2">
|
||||
<div class="col-md-4 col-sm-auto mb-2">
|
||||
<ul class="list-group list-group-flush">
|
||||
<li class="list-group-item">
|
||||
<strong>{% trans "Name" %}:</strong> {{ vendor.get_local_name }} </li>
|
||||
@ -55,6 +58,43 @@
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4 col-sm-auto mb-sm-2">
|
||||
|
||||
|
||||
<div class="table-responsive overflow-auto" style="max-height:250px;">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">{% trans "Make" %}</th>
|
||||
<th scope="col">{% trans "Total Cars Purchased" %}</th>
|
||||
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for make in vendor_makes%}
|
||||
<tr>
|
||||
|
||||
<td class="align-middle">{{ make.id_car_make__name }}</td>
|
||||
<td class="align-middle ">{{make.make_count}}</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
|
||||
<tr>
|
||||
<td colspan="2" class="text-center text-muted">{% trans "There is no Purchase from this vendor yet" %}</td>
|
||||
|
||||
</tr>
|
||||
|
||||
|
||||
{% endfor %}
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -86,7 +126,7 @@
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr>
|
||||
<td colspan="6" class="text-center text-muted">{% trans "No Bills Found For the Vendor: {vendor.get_local_name}" %}</td>
|
||||
<td colspan="6" class="text-center text-muted">{% trans "No Bills Found For the Vendor : " %}{{vendor.get_local_name}}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user