staff name fields removed
This commit is contained in:
parent
caae2925bf
commit
ce644d9d33
@ -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):
|
||||
@ -3720,7 +3720,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 +5027,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 +5036,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 +7046,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 +11065,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 +11089,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 +11104,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 +11182,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
|
||||
|
||||
@ -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>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user