From c87a22b1036db80d810cfcf5348a6225a4c9fcf2 Mon Sep 17 00:00:00 2001 From: Faheedkhan Date: Thu, 28 Aug 2025 14:07:41 +0300 Subject: [PATCH] updated --- inventory/views.py | 697 +-------------------------------------------- 1 file changed, 5 insertions(+), 692 deletions(-) diff --git a/inventory/views.py b/inventory/views.py index 4c2a1082..0f15e2c7 100644 --- a/inventory/views.py +++ b/inventory/views.py @@ -18,7 +18,6 @@ from decimal import Decimal from io import TextIOWrapper from django.apps import apps from datetime import datetime, timedelta,date -from datetime import datetime, timedelta,date from calendar import month_name from pyzbar.pyzbar import decode from urllib.parse import urlparse, urlunparse @@ -109,7 +108,6 @@ from django_ledger.forms.bank_account import ( ) from django_ledger.views.chart_of_accounts import ( ChartOfAccountModelListView as ChartOfAccountModelListViewBase - ChartOfAccountModelListView as ChartOfAccountModelListViewBase ) from django_ledger.views.bill import ( BillModelCreateView, @@ -176,7 +174,6 @@ from django_ledger.models import ( LedgerModel, PurchaseOrderModel, ChartOfAccountModel - ChartOfAccountModel ) from django_ledger.views.financial_statement import ( FiscalYearBalanceSheetView, @@ -408,7 +405,6 @@ class TestView(TemplateView): template_name = "inventory/cars_list_api.html" @login_required -def general_dashboard(request,dealer_slug): def general_dashboard(request,dealer_slug): """ Renders the dealer dashboard with key performance indicators and chart data. @@ -416,9 +412,6 @@ def general_dashboard(request,dealer_slug): dealer = get_object_or_404(models.Dealer,slug=dealer_slug) vat = models.VatRate.objects.filter(dealer=dealer,is_active=True).first() VAT_RATE=vat.rate - dealer = get_object_or_404(models.Dealer,slug=dealer_slug) - vat = models.VatRate.objects.filter(dealer=dealer,is_active=True).first() - VAT_RATE=vat.rate today_local = timezone.localdate() # ---------------------------------------------------- @@ -426,14 +419,10 @@ def general_dashboard(request,dealer_slug): # ---------------------------------------------------- start_date_str = request.GET.get('start_date') end_date_str = request.GET.get('end_date') - start_date_str = request.GET.get('start_date') - end_date_str = request.GET.get('end_date') if start_date_str and end_date_str: start_date = timezone.datetime.strptime(start_date_str, '%Y-%m-%d').date() end_date = timezone.datetime.strptime(end_date_str, '%Y-%m-%d').date() - start_date = timezone.datetime.strptime(start_date_str, '%Y-%m-%d').date() - end_date = timezone.datetime.strptime(end_date_str, '%Y-%m-%d').date() else: start_date = today_local - timedelta(days=30) end_date = today_local @@ -442,25 +431,18 @@ def general_dashboard(request,dealer_slug): # 2. Inventory KPIs # ---------------------------------------------------- active_cars = models.Car.objects.filter(dealer=dealer).exclude(status='sold') - active_cars = models.Car.objects.filter(dealer=dealer).exclude(status='sold') total_cars_in_inventory = active_cars.count() total_inventory_value = active_cars.aggregate(total=Sum('cost_price'))['total'] or 0 new_cars_qs = active_cars.filter(stock_type='new') - total_inventory_value = active_cars.aggregate(total=Sum('cost_price'))['total'] or 0 - new_cars_qs = active_cars.filter(stock_type='new') total_new_cars_in_inventory = new_cars_qs.count() new_car_value = new_cars_qs.aggregate(total=Sum('cost_price'))['total'] or 0 used_cars_qs = active_cars.filter(stock_type='used') - new_car_value = new_cars_qs.aggregate(total=Sum('cost_price'))['total'] or 0 - used_cars_qs = active_cars.filter(stock_type='used') total_used_cars_in_inventory = used_cars_qs.count() used_car_value = used_cars_qs.aggregate(total=Sum('cost_price'))['total'] or 0 - used_car_value = used_cars_qs.aggregate(total=Sum('cost_price'))['total'] or 0 aging_threshold_days = 60 aging_inventory_count = active_cars.filter(receiving_date__date__lte=today_local - timedelta(days=aging_threshold_days)).count() - aging_inventory_count = active_cars.filter(receiving_date__date__lte=today_local - timedelta(days=aging_threshold_days)).count() # ---------------------------------------------------- # 3. Sales KPIs (filtered by date) @@ -468,10 +450,8 @@ def general_dashboard(request,dealer_slug): cars_sold_filtered = models.Car.objects.filter( dealer=dealer, status='sold', - status='sold', sold_date__date__gte=start_date, sold_date__date__lte=end_date - sold_date__date__lte=end_date ) # General sales KPIs @@ -480,39 +460,23 @@ def general_dashboard(request,dealer_slug): total_revenue_from_cars = cars_sold_filtered.aggregate( total=Sum(F('marked_price') - F('discount_amount')) )['total'] or 0 - total_cost_of_cars_sold = cars_sold_filtered.aggregate(total=Sum('cost_price'))['total'] or 0 - total_revenue_from_cars = cars_sold_filtered.aggregate( - total=Sum(F('marked_price') - F('discount_amount')) - )['total'] or 0 - total_vat_collected_from_cars = cars_sold_filtered.annotate( - final_price=F('marked_price') - F('discount_amount')).aggregate( - total=Sum(F('final_price') * VAT_RATE))['total'] or 0 total_vat_collected_from_cars = cars_sold_filtered.annotate( final_price=F('marked_price') - F('discount_amount')).aggregate( total=Sum(F('final_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 - total_discount = cars_sold_filtered.aggregate(total=Sum('discount_amount'))['total'] or 0 # Sales breakdown by type new_cars_sold = cars_sold_filtered.filter(stock_type='new') - new_cars_sold = cars_sold_filtered.filter(stock_type='new') total_new_cars_sold = new_cars_sold.count() total_cost_of_new_cars_sold = new_cars_sold.aggregate(total=Sum('cost_price'))['total'] or 0 - total_cost_of_new_cars_sold = new_cars_sold.aggregate(total=Sum('cost_price'))['total'] or 0 # total_revenue_from_new_cars=sum([ car.final_price for car in new_cars_sold]) total_revenue_from_new_cars = new_cars_sold.aggregate( total=Sum(F('marked_price') - F('discount_amount')) )['total'] or 0 - total_revenue_from_new_cars = new_cars_sold.aggregate( - total=Sum(F('marked_price') - F('discount_amount')) - )['total'] or 0 - total_vat_collected_from_new_cars = new_cars_sold.annotate( - final_price=F('marked_price') - F('discount_amount')).aggregate( - total=Sum(F('final_price') * VAT_RATE))['total'] or 0 total_vat_collected_from_new_cars = new_cars_sold.annotate( final_price=F('marked_price') - F('discount_amount')).aggregate( total=Sum(F('final_price') * VAT_RATE))['total'] or 0 @@ -521,41 +485,25 @@ def general_dashboard(request,dealer_slug): - used_cars_sold = cars_sold_filtered.filter(stock_type='used') - - used_cars_sold = cars_sold_filtered.filter(stock_type='used') total_used_cars_sold = used_cars_sold.count() total_cost_of_used_cars_sold = used_cars_sold.aggregate(total=Sum('cost_price'))['total'] or 0 total_revenue_from_used_cars = used_cars_sold.aggregate( total=Sum(F('marked_price') - F('discount_amount')) )['total'] or 0 - total_cost_of_used_cars_sold = used_cars_sold.aggregate(total=Sum('cost_price'))['total'] or 0 - total_revenue_from_used_cars = used_cars_sold.aggregate( - total=Sum(F('marked_price') - F('discount_amount')) - )['total'] or 0 - total_vat_collected_from_used_cars = used_cars_sold.annotate( - final_price=F('marked_price') - F('discount_amount')).aggregate( - total=Sum(F('final_price') * VAT_RATE))['total'] or 0 total_vat_collected_from_used_cars = used_cars_sold.annotate( final_price=F('marked_price') - F('discount_amount')).aggregate( total=Sum(F('final_price') * VAT_RATE))['total'] or 0 net_profit_from_used_cars = total_revenue_from_used_cars - total_cost_of_used_cars_sold - net_profit_from_used_cars = total_revenue_from_used_cars - total_cost_of_used_cars_sold # Service & Overall KPIs total_revenue_from_services = sum([car.get_additional_services()['total'] for car in cars_sold_filtered]) total_vat_collected_from_services = sum([car.get_additional_services()['services_vat'] for car in cars_sold_filtered]) total_vat_collected = total_vat_collected_from_cars + total_vat_collected_from_services - total_revenue_from_services = sum([car.get_additional_services()['total'] for car in cars_sold_filtered]) - total_vat_collected_from_services = sum([car.get_additional_services()['services_vat'] for car in cars_sold_filtered]) - total_vat_collected = total_vat_collected_from_cars + total_vat_collected_from_services total_revenue_generated = total_revenue_from_cars + total_revenue_from_services - expenses = models.ItemModel.objects.filter(entity__admin__dealer=dealer, item_role='expense') - total_expenses = expenses.aggregate(total=Sum('default_amount'))['total'] or 0 expenses = models.ItemModel.objects.filter(entity__admin__dealer=dealer, item_role='expense') total_expenses = expenses.aggregate(total=Sum('default_amount'))['total'] or 0 gross_profit = net_profit_from_cars - total_expenses @@ -570,13 +518,6 @@ def general_dashboard(request,dealer_slug): total_revenue=Sum(F('marked_price') - F('discount_amount')), total_profit=Sum(F('marked_price') - F('discount_amount') - F('cost_price')) ).order_by('month') - monthly_sales_data = cars_sold_filtered.annotate( - month=ExtractMonth('sold_date') - ).values('month').annotate( - total_cars=Count('pk'), - total_revenue=Sum(F('marked_price') - F('discount_amount')), - total_profit=Sum(F('marked_price') - F('discount_amount') - F('cost_price')) - ).order_by('month') monthly_cars_sold = [0] * 12 monthly_revenue = [0] * 12 @@ -587,10 +528,6 @@ def general_dashboard(request,dealer_slug): monthly_cars_sold[month_index] = data['total_cars'] monthly_revenue[month_index] = float(data['total_revenue']) if data['total_revenue'] else 0 monthly_net_profit[month_index] = float(data['total_profit']) if data['total_profit'] else 0 - month_index = data['month'] - 1 - monthly_cars_sold[month_index] = data['total_cars'] - monthly_revenue[month_index] = float(data['total_revenue']) if data['total_revenue'] else 0 - monthly_net_profit[month_index] = float(data['total_profit']) if data['total_profit'] else 0 monthly_cars_sold_json = json.dumps(monthly_cars_sold) monthly_revenue_json = json.dumps(monthly_revenue) @@ -602,13 +539,6 @@ def general_dashboard(request,dealer_slug): sales_by_make_data = cars_sold_filtered.values('id_car_make__name').annotate( car_count=Count('id_car_make__name') ).order_by('-car_count') - sales_by_make_data = cars_sold_filtered.values('id_car_make__name').annotate( - car_count=Count('id_car_make__name') - ).order_by('-car_count') - - 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] - 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] @@ -620,16 +550,12 @@ def general_dashboard(request,dealer_slug): # ---------------------------------------------------- - # Get the selected make from the URL query parameter selected_make_sales= request.GET.get('make_sold', None) - selected_make_sales= request.GET.get('make_sold', None) - # Get a list of all unique makes for the dropdown all_makes_sold = list(cars_sold_filtered.values_list('id_car_make__name', flat=True).distinct().order_by('id_car_make__name')) - all_makes_sold = list(cars_sold_filtered.values_list('id_car_make__name', flat=True).distinct().order_by('id_car_make__name')) if selected_make_sales: # If a make is selected, filter the queryset @@ -638,11 +564,6 @@ def general_dashboard(request,dealer_slug): ).values('id_car_model__name').annotate( count=Count('id_car_model__name') ).order_by('-count') - sales_data_by_model = cars_sold_filtered.filter( - id_car_make__name=selected_make_sales - ).values('id_car_model__name').annotate( - count=Count('id_car_model__name') - ).order_by('-count') else: # If no make is selected, pass an empty list or some default data sales_data_by_model = [] @@ -650,30 +571,20 @@ def general_dashboard(request,dealer_slug): - - - # 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_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] 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] # 2. Inventory by Model (Bar Chart) selected_make_inventory = request.GET.get('make_inventory', None) - selected_make_inventory = request.GET.get('make_inventory', None) # Get all unique makes in inventory for the dropdown all_makes_inventory = list(active_cars.values_list('id_car_make__name', flat=True).distinct().order_by('id_car_make__name')) - all_makes_inventory = list(active_cars.values_list('id_car_make__name', flat=True).distinct().order_by('id_car_make__name')) if selected_make_inventory: inventory_data_by_model = active_cars.filter( @@ -681,11 +592,6 @@ def general_dashboard(request,dealer_slug): ).values('id_car_model__name').annotate( count=Count('id_car_model__name') ).order_by('-count') - inventory_data_by_model = active_cars.filter( - id_car_make__name=selected_make_inventory - ).values('id_car_model__name').annotate( - count=Count('id_car_model__name') - ).order_by('-count') else: # Default data inventory_data_by_model = [] @@ -695,10 +601,6 @@ def general_dashboard(request,dealer_slug): 'end_date': end_date, 'today': today_local, - 'start_date': start_date, - 'end_date': end_date, - 'today': today_local, - # Inventory KPIs 'total_cars_in_inventory': total_cars_in_inventory, 'total_inventory_value': total_inventory_value, @@ -708,14 +610,6 @@ def general_dashboard(request,dealer_slug): 'used_car_value': used_car_value, 'aging_inventory_count': aging_inventory_count, - 'total_cars_in_inventory': total_cars_in_inventory, - 'total_inventory_value': total_inventory_value, - 'total_new_cars_in_inventory': total_new_cars_in_inventory, - 'total_used_cars_in_inventory': total_used_cars_in_inventory, - 'new_car_value': new_car_value, - 'used_car_value': used_car_value, - 'aging_inventory_count': aging_inventory_count, - # Sales KPIs 'total_cars_sold': total_cars_sold, 'total_cost_of_cars_sold': total_cost_of_cars_sold, @@ -724,13 +618,6 @@ def general_dashboard(request,dealer_slug): 'total_vat_collected_from_cars': total_vat_collected_from_cars, 'total_discount_on_cars': total_discount, - 'total_cars_sold': total_cars_sold, - 'total_cost_of_cars_sold': total_cost_of_cars_sold, - 'total_revenue_from_cars': total_revenue_from_cars, - 'net_profit_from_cars': net_profit_from_cars, - 'total_vat_collected_from_cars': total_vat_collected_from_cars, - 'total_discount_on_cars': total_discount, - # Sales by Type 'total_new_cars_sold': total_new_cars_sold, 'total_used_cars_sold': total_used_cars_sold, @@ -743,17 +630,6 @@ def general_dashboard(request,dealer_slug): 'net_profit_from_used_cars': net_profit_from_used_cars, 'total_vat_collected_from_used_cars': total_vat_collected_from_used_cars, - 'total_new_cars_sold': total_new_cars_sold, - 'total_used_cars_sold': total_used_cars_sold, - 'total_cost_of_new_cars_sold': total_cost_of_new_cars_sold, - 'total_revenue_from_new_cars': total_revenue_from_new_cars, - 'net_profit_from_new_cars': net_profit_from_new_cars, - 'total_vat_collected_from_new_cars': total_vat_collected_from_new_cars, - 'total_cost_of_used_cars_sold': total_cost_of_used_cars_sold, - 'total_revenue_from_used_cars': total_revenue_from_used_cars, - 'net_profit_from_used_cars': net_profit_from_used_cars, - 'total_vat_collected_from_used_cars': total_vat_collected_from_used_cars, - # Services and Overall KPIs 'total_revenue_from_services': total_revenue_from_services, 'total_vat_collected_from_services': total_vat_collected_from_services, @@ -762,28 +638,8 @@ def general_dashboard(request,dealer_slug): 'total_expenses': total_expenses, 'gross_profit': gross_profit, - 'total_revenue_from_services': total_revenue_from_services, - 'total_vat_collected_from_services': total_vat_collected_from_services, - 'total_revenue_generated': total_revenue_generated, - 'total_vat_collected': total_vat_collected, - 'total_expenses': total_expenses, - 'gross_profit': gross_profit, - # Chart Data - 'monthly_cars_sold_json': monthly_cars_sold_json, - '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)), - - 'monthly_cars_sold_json': monthly_cars_sold_json, 'monthly_revenue_json': monthly_revenue_json, 'monthly_net_profit_json': monthly_net_profit_json, @@ -804,24 +660,13 @@ def general_dashboard(request,dealer_slug): 'inventory_data_by_model_json': json.dumps(list(inventory_data_by_model)), - 'inventory_by_make_labels_json': json.dumps(inventory_by_make_labels), - 'inventory_by_make_counts_json': json.dumps(inventory_by_make_counts), - 'all_makes_inventory': all_makes_inventory, - '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) return render(request, 'dashboards/general_dashboard.html', context) @login_required -def sales_dashboard(request,dealer_slug): - dealer = get_object_or_404(models.Dealer,slug=dealer_slug) def sales_dashboard(request,dealer_slug): dealer = get_object_or_404(models.Dealer,slug=dealer_slug) today_local = timezone.localdate() @@ -831,14 +676,10 @@ def sales_dashboard(request,dealer_slug): # ---------------------------------------------------- start_date_str = request.GET.get('start_date') end_date_str = request.GET.get('end_date') - start_date_str = request.GET.get('start_date') - end_date_str = request.GET.get('end_date') if start_date_str and end_date_str: start_date = timezone.datetime.strptime(start_date_str, '%Y-%m-%d').date() end_date = timezone.datetime.strptime(end_date_str, '%Y-%m-%d').date() - start_date = timezone.datetime.strptime(start_date_str, '%Y-%m-%d').date() - end_date = timezone.datetime.strptime(end_date_str, '%Y-%m-%d').date() else: start_date = today_local - timedelta(days=30) end_date = today_local @@ -848,13 +689,9 @@ def sales_dashboard(request,dealer_slug): dealer=dealer, created__date__gte=start_date, created__date__lte=end_date - dealer=dealer, - created__date__gte=start_date, - created__date__lte=end_date ) - # ---------------------------------------------------- # 2. Lead Sources Chart Logic # ---------------------------------------------------- @@ -863,15 +700,10 @@ def sales_dashboard(request,dealer_slug): lead_sources_data = leads_filtered.values('source').annotate( count=Count('source') ).order_by('-count') - lead_sources_data = leads_filtered.values('source').annotate( - count=Count('source') - ).order_by('-count') # Separate the labels and counts for the chart lead_sources_labels = [item['source'] for item in lead_sources_data] lead_sources_counts = [item['count'] for item in lead_sources_data] - lead_sources_labels = [item['source'] for item in lead_sources_data] - lead_sources_counts = [item['count'] for item in lead_sources_data] # ---------------------------------------------------- # 2. Lead Funnel Chart Logic @@ -880,9 +712,6 @@ def sales_dashboard(request,dealer_slug): dealer=dealer, created__date__gte=start_date, created__date__lte=end_date - dealer=dealer, - created__date__gte=start_date, - created__date__lte=end_date ) opportunity_stage_data = opportunity_filtered.values('stage').annotate( count=Count('stage') @@ -891,31 +720,19 @@ def sales_dashboard(request,dealer_slug): opportunity_stage_labels = [item['stage'] for item in opportunity_stage_data ] opportunity_stage_counts = [item['count'] for item in opportunity_stage_data ] - opportunity_stage_data = opportunity_filtered.values('stage').annotate( - count=Count('stage') - ).order_by('-count') - # Separate the labels and counts for the chart - opportunity_stage_labels = [item['stage'] for item in opportunity_stage_data ] - opportunity_stage_counts = [item['count'] for item in opportunity_stage_data ] - # 2. Inventory KPIs # ---------------------------------------------------- active_cars = models.Car.objects.filter(dealer=dealer).exclude(status='sold') - active_cars = models.Car.objects.filter(dealer=dealer).exclude(status='sold') total_cars_in_inventory = active_cars.count() new_cars_qs = active_cars.filter(stock_type='new') - new_cars_qs = active_cars.filter(stock_type='new') total_new_cars_in_inventory = new_cars_qs.count() used_cars_qs = active_cars.filter(stock_type='used') - used_cars_qs = active_cars.filter(stock_type='used') total_used_cars_in_inventory = used_cars_qs.count() aging_threshold_days = 60 aging_inventory_count = active_cars.filter(receiving_date__date__lte=today_local - timedelta(days=aging_threshold_days)).count() - aging_inventory_count = active_cars.filter(receiving_date__date__lte=today_local - timedelta(days=aging_threshold_days)).count() - context = { 'start_date': start_date, @@ -930,26 +747,11 @@ def sales_dashboard(request,dealer_slug): 'total_new_cars_in_inventory': total_new_cars_in_inventory, 'total_used_cars_in_inventory': total_used_cars_in_inventory, 'aging_inventory_count': aging_inventory_count, - 'start_date': start_date, - 'end_date': end_date, - 'lead_sources_labels_json': json.dumps(lead_sources_labels), - 'lead_sources_counts_json': json.dumps(lead_sources_counts), - 'opportunity_stage_labels_json': json.dumps(opportunity_stage_labels), - 'opportunity_stage_counts_json': json.dumps(opportunity_stage_counts), - - # Inventory KPIs - 'total_cars_in_inventory': total_cars_in_inventory, - 'total_new_cars_in_inventory': total_new_cars_in_inventory, - 'total_used_cars_in_inventory': total_used_cars_in_inventory, - 'aging_inventory_count': aging_inventory_count, } return render(request, 'dashboards/sales_dashboard.html', context) - return render(request, 'dashboards/sales_dashboard.html', context) - - def aging_inventory_list_view(request, dealer_slug): @@ -966,54 +768,34 @@ def aging_inventory_list_view(request, dealer_slug): selected_series = request.GET.get('series') # Changed 'serie' to 'series' for consistency selected_year = request.GET.get('year') selected_stock_type = request.GET.get('stock_type') - selected_make = request.GET.get('make') - selected_model = request.GET.get('model') - selected_series = request.GET.get('series') # Changed 'serie' to 'series' for consistency - selected_year = request.GET.get('year') - selected_stock_type = request.GET.get('stock_type') # Start with the base queryset for all aging cars. aging_cars_queryset = models.Car.objects.filter( dealer=dealer, 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'] - 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) - aging_cars_queryset = aging_cars_queryset.filter(id_car_make__name=selected_make) if selected_model: aging_cars_queryset = aging_cars_queryset.filter(id_car_model__name=selected_model) - aging_cars_queryset = aging_cars_queryset.filter(id_car_model__name=selected_model) if selected_series: aging_cars_queryset = aging_cars_queryset.filter(id_car_series__name=selected_series) - aging_cars_queryset = aging_cars_queryset.filter(id_car_series__name=selected_series) if selected_year: aging_cars_queryset = aging_cars_queryset.filter(id_car_year__year=selected_year) - 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. aging_base_queryset = models.Car.objects.filter( dealer=dealer, receiving_date__date__lt=today_local - timedelta(days=aging_threshold_days) ).exclude(status='sold') - 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') 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') @@ -1024,7 +806,6 @@ def aging_inventory_list_view(request, dealer_slug): # Set up pagination paginator = Paginator(aging_cars_queryset, 10) page_number = request.GET.get('page') - 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. @@ -1046,22 +827,9 @@ def aging_inventory_list_view(request, dealer_slug): 'all_years': all_years, 'total_aging_inventory_value':total_aging_inventory_value - 'selected_make': selected_make, - 'selected_model': selected_model, - 'selected_series': selected_series, # Corrected variable name - 'selected_year': selected_year, - 'selected_stock_type': selected_stock_type, - 'all_makes': all_makes, - 'all_models': all_models, - 'all_series': all_series, - '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) - return render(request, 'dashboards/aging_inventory_list.html', context) def terms_and_privacy(request): return render(request, "terms_and_privacy.html") @@ -1086,7 +854,6 @@ def WelcomeView(request): return render(request, "welcome.html", context) -class CarCreateView(LoginRequiredMixin, PermissionRequiredMixin,SuccessMessageMixin, CreateView): class CarCreateView(LoginRequiredMixin, PermissionRequiredMixin,SuccessMessageMixin, CreateView): """ Manages the creation of a new car entry in the inventory system. @@ -1110,7 +877,6 @@ class CarCreateView(LoginRequiredMixin, PermissionRequiredMixin,SuccessMessageMi template_name = "inventory/car_form.html" permission_required = ["inventory.add_car"] success_message=_("Car Added successfully to the inventory") - success_message=_("Car Added successfully to the inventory") def get_form(self, form_class=None): form = super().get_form(form_class) @@ -1508,7 +1274,6 @@ class CarInventory(LoginRequiredMixin, PermissionRequiredMixin, ListView): return context -class CarColorCreate(LoginRequiredMixin, PermissionRequiredMixin,SuccessMessageMixin, CreateView): class CarColorCreate(LoginRequiredMixin, PermissionRequiredMixin,SuccessMessageMixin, CreateView): """ View for creating a new car color. @@ -1534,7 +1299,6 @@ class CarColorCreate(LoginRequiredMixin, PermissionRequiredMixin,SuccessMessageM template_name = "inventory/add_colors.html" permission_required = ["inventory.add_carcolors"] success_message=_("Car colors details added successfully") - success_message=_("Car colors details added successfully") def form_valid(self, form): car = get_object_or_404(models.Car, slug=self.kwargs["slug"]) @@ -1967,7 +1731,6 @@ class CarDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView): permission_required = ["inventory.view_car"] -def CarFinanceUpdateView(request,dealer_slug,slug): def CarFinanceUpdateView(request,dealer_slug,slug): car = get_object_or_404(models.Car, slug=slug) dealer = get_object_or_404(models.Dealer, slug=dealer_slug) @@ -1983,7 +1746,6 @@ def CarFinanceUpdateView(request,dealer_slug,slug): form = forms.CarFinanceForm(instance=car) return render(request, "inventory/car_finance_form.html", {"car": car, "dealer": dealer, "form": form}) - return render(request, "inventory/car_finance_form.html", {"car": car, "dealer": dealer, "form": form}) class CarUpdateView( LoginRequiredMixin, PermissionRequiredMixin, SuccessMessageMixin, UpdateView @@ -2015,7 +1777,6 @@ class CarUpdateView( def get_success_url(self): return reverse("car_detail", kwargs={"dealer_slug": self.request.dealer.slug,"slug": self.object.slug}) - return reverse("car_detail", kwargs={"dealer_slug": self.request.dealer.slug,"slug": self.object.slug}) def get_form(self, form_class=None): form = super().get_form(form_class) @@ -2613,7 +2374,6 @@ class DealerUpdateView( def get_success_url(self): return reverse("dealer_detail", kwargs={"slug": self.object.slug}) -class StaffDetailView(LoginRequiredMixin, DetailView): class StaffDetailView(LoginRequiredMixin, DetailView): """ Represents a detailed view for a Dealer model. @@ -2637,7 +2397,6 @@ class StaffDetailView(LoginRequiredMixin, DetailView): - def dealer_vat_rate_update(request, slug): dealer = get_object_or_404(models.Dealer, slug=slug) models.VatRate.objects.filter(dealer=dealer).update(rate=request.POST.get("rate")) @@ -2766,15 +2525,11 @@ class CustomerDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView context["notes"] = models.Notes.objects.filter( dealer=dealer, content_type__model="customer", object_id=self.object.id - dealer=dealer, - content_type__model="customer", object_id=self.object.id ) estimates = entity.get_estimates().filter(customer=self.object.customer_model) invoices = entity.get_invoices().filter(customer=self.object.customer_model) context['leads']=self.object.customer_leads.all() - context['leads']=self.object.customer_leads.all() - total = estimates.count() + invoices.count() @@ -2891,8 +2646,6 @@ class CustomerCreateView( if customer := models.Customer.objects.filter( dealer=dealer, email=form.instance.email - dealer=dealer, - email=form.instance.email ).first(): if not customer.active: messages.error( @@ -3077,18 +2830,10 @@ def vendorDetailView(request, dealer_slug, slug): 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) - 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) - page_obj=paginator.get_page(page_number) return render( 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} - 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} ) @@ -3125,7 +2870,6 @@ class VendorCreateView( def form_valid(self, form): dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"]) - if vendor := models.Vendor.objects.filter(dealer=dealer,email=form.instance.email).first(): if vendor := models.Vendor.objects.filter(dealer=dealer,email=form.instance.email).first(): if not vendor.active: messages.error( @@ -3915,7 +3659,6 @@ class UserCreateView( # staff_member, _ = StaffMember.objects.get_or_create(user=user) # for service in form.cleaned_data["service_offered"]: # staff_member.services_offered.add(service) - # staff_member.services_offered.add(service) staff.user = user staff.dealer = dealer staff.save() @@ -3925,7 +3668,6 @@ class UserCreateView( return super().form_valid(form) def get_success_url(self): - return reverse_lazy("staff_password_reset", args=[self.request.dealer.slug, self.staff_pk]) return reverse_lazy("staff_password_reset", args=[self.request.dealer.slug, self.staff_pk]) # return reverse_lazy("user_list", args=[self.request.dealer.slug]) @@ -4112,8 +3854,6 @@ class OrganizationCreateView(LoginRequiredMixin, PermissionRequiredMixin, Create if organization := models.Organization.objects.filter( dealer=dealer, email=form.instance.email - dealer=dealer, - email=form.instance.email ).first(): if not organization.active: messages.error( @@ -4691,16 +4431,13 @@ class AccountCreateView( def get_success_url(self): return reverse( "account_list", kwargs={"dealer_slug": self.kwargs["dealer_slug"], "coa_pk": self.kwargs["coa_pk"]} - "account_list", kwargs={"dealer_slug": self.kwargs["dealer_slug"], "coa_pk": self.kwargs["coa_pk"]} ) - def get_context_data(self,**kwargs): def get_context_data(self,**kwargs): context = super().get_context_data(**kwargs) context["url_kwargs"] = self.kwargs coa_pk = context["url_kwargs"]["coa_pk"] try: kwargs["coa_model"] = ChartOfAccountModel.objects.get(pk=coa_pk) or self.request.entity.get_default_coa() - kwargs["coa_model"] = ChartOfAccountModel.objects.get(pk=coa_pk) or self.request.entity.get_default_coa() except Exception: kwargs["coa_model"] = self.request.entity.get_default_coa() return context @@ -4806,23 +4543,19 @@ class AccountUpdateView( def get_success_url(self): return reverse_lazy( "account_list", kwargs={"dealer_slug": self.kwargs["dealer_slug"],"coa_pk":self.kwargs["coa_pk"]} - "account_list", kwargs={"dealer_slug": self.kwargs["dealer_slug"],"coa_pk":self.kwargs["coa_pk"]} ) - def get_context_data(self,**kwargs): def get_context_data(self,**kwargs): context = super().get_context_data(**kwargs) context["url_kwargs"] = self.kwargs coa_pk = context["url_kwargs"]["coa_pk"] try: kwargs["coa_model"] = ChartOfAccountModel.objects.get(pk=coa_pk) or self.request.entity.get_default_coa() - kwargs["coa_model"] = ChartOfAccountModel.objects.get(pk=coa_pk) or self.request.entity.get_default_coa() except Exception: kwargs["coa_model"] = self.request.entity.get_default_coa() return context @login_required @permission_required("django_ledger.delete_accountmodel") -def account_delete(request, dealer_slug,coa_pk, pk): def account_delete(request, dealer_slug,coa_pk, pk): """ Handles the deletion of an account object identified by its primary key (pk). Ensures @@ -4869,21 +4602,16 @@ def sales_list_view(request, dealer_slug): try: if any([request.is_dealer, request.is_manager, request.is_accountant]): qs = models.ExtraInfo.get_sale_orders(staff=staff, is_dealer=True,dealer=dealer) - qs = models.ExtraInfo.get_sale_orders(staff=staff, is_dealer=True,dealer=dealer) elif request.is_staff: qs = models.ExtraInfo.get_sale_orders(staff=staff,dealer=dealer) - qs = models.ExtraInfo.get_sale_orders(staff=staff,dealer=dealer) except Exception as e: print(e) - search_query = request.GET.get('q', None) search_query = request.GET.get('q', None) if search_query: qs = qs.filter( Q(order_number__icontains=search_query)| Q(customer__customer_name__icontains=search_query) - Q(order_number__icontains=search_query)| - Q(customer__customer_name__icontains=search_query) ).distinct() paginator = Paginator(qs, 30) @@ -4976,11 +4704,6 @@ class EstimateListView(LoginRequiredMixin, PermissionRequiredMixin, ListView): content_type=ContentType.objects.get_for_model(EstimateModel), related_content_type=ContentType.objects.get_for_model(User), )) - ).union(models.ExtraInfo.objects.filter( - dealer=dealer, - content_type=ContentType.objects.get_for_model(EstimateModel), - related_content_type=ContentType.objects.get_for_model(User), - )) elif self.request.is_staff and self.request.is_sales: qs = models.ExtraInfo.objects.filter( @@ -4991,13 +4714,10 @@ class EstimateListView(LoginRequiredMixin, PermissionRequiredMixin, ListView): ) qs = EstimateModel.objects.filter(pk__in=[x.content_object.pk for x in qs]) search_query = self.request.GET.get('q', None) - search_query = self.request.GET.get('q', None) if search_query: qs = qs.filter( Q(estimate_number__icontains=search_query)| Q(customer__customer_name__icontains=search_query) - Q(estimate_number__icontains=search_query)| - Q(customer__customer_name__icontains=search_query) ).distinct() context["staff_estimates"] = qs return context @@ -5011,14 +4731,11 @@ class EstimateListView(LoginRequiredMixin, PermissionRequiredMixin, ListView): if status: queryset = queryset.filter(status=status) search_query = self.request.GET.get('q', None) - search_query = self.request.GET.get('q', None) if search_query: queryset = queryset.filter( Q(estimate_number__icontains=search_query)| Q(customer__customer_name__icontains=search_query) - Q(estimate_number__icontains=search_query)| - Q(customer__customer_name__icontains=search_query) ).distinct() return queryset @@ -5056,7 +4773,6 @@ def create_estimate(request, dealer_slug, slug=None): title = data.get("title") customer_id = data.get("customer") customer = models.Customer.objects.filter(pk=int(customer_id),dealer=dealer).first() - customer = models.Customer.objects.filter(pk=int(customer_id),dealer=dealer).first() items = data.get("item", []) quantities = data.get("quantity", []) @@ -5148,7 +4864,6 @@ def create_estimate(request, dealer_slug, slug=None): "unit_cost": round(float(i.marked_price)), "unit_revenue": round(float(i.marked_price)), "total_amount": round(float(i.final_price_plus_vat)),# TODO : check later - "total_amount": round(float(i.final_price_plus_vat)),# TODO : check later } ) @@ -5327,7 +5042,6 @@ class EstimateDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView # calculator = CarFinanceCalculator(estimate) # finance_data = calculator.get_finance_data() finance_data = get_finance_data(estimate,dealer) - finance_data = get_finance_data(estimate,dealer) invoice_obj = InvoiceModel.objects.all().filter(ce_model=estimate).first() kwargs["data"] = finance_data @@ -5338,7 +5052,6 @@ class EstimateDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView 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: @@ -5356,7 +5069,6 @@ class EstimatePrintView(EstimateDetailView): - @login_required @permission_required("inventory.add_saleorder", raise_exception=True) def create_sale_order(request, dealer_slug, pk): @@ -5410,8 +5122,6 @@ def create_sale_order(request, dealer_slug, pk): pass item.item_model.car.sold_date=timezone.now() # to be checked added by faheed item.item_model.car.save()# to be checked added byfaheed - item.item_model.car.sold_date=timezone.now() # to be checked added by faheed - item.item_model.car.save()# to be checked added byfaheed item.item_model.car.mark_as_sold() messages.success(request, "Sale Order created successfully") @@ -5433,7 +5143,6 @@ def create_sale_order(request, dealer_slug, pk): # calculator = CarFinanceCalculator(estimate) finance_data = get_finance_data(estimate,dealer) - finance_data = get_finance_data(estimate,dealer) return render( request, "sales/estimates/sale_order_form.html", @@ -5456,15 +5165,10 @@ def update_estimate_discount(request, dealer_slug, pk): discount_amount = request.POST.get("discount_amount", 0) finance_data = get_finance_data(estimate,dealer) car = finance_data.get('car') - finance_data = get_finance_data(estimate,dealer) - car = finance_data.get('car') if Decimal(discount_amount) >= car.marked_price: - messages.error(request, _("Discount amount cannot be greater than marked price")) messages.error(request, _("Discount amount cannot be greater than marked price")) return redirect("estimate_detail", dealer_slug=dealer_slug, pk=pk) - if Decimal(discount_amount) > car.marked_price * Decimal('0.5'): - messages.warning(request, _("Discount amount is greater than 50% of the marked price, proceed with caution.")) if Decimal(discount_amount) > car.marked_price * Decimal('0.5'): messages.warning(request, _("Discount amount is greater than 50% of the marked price, proceed with caution.")) else: @@ -5486,9 +5190,6 @@ def update_estimate_additionals(request, dealer_slug, pk): car.additional_services.set( form.cleaned_data["additional_finances"] ) - car.additional_services.set( - form.cleaned_data["additional_finances"] - ) car.save() messages.success(request, "Additional Finances updated successfully") return redirect("estimate_detail", dealer_slug=dealer_slug, pk=pk) @@ -5514,7 +5215,6 @@ class SaleOrderDetail(LoginRequiredMixin, PermissionRequiredMixin, DetailView): # calculator = CarFinanceCalculator(estimate) # finance_data = calculator.get_finance_data() finance_data = get_finance_data(estimate,dealer) - finance_data = get_finance_data(estimate,dealer) kwargs["data"] = finance_data return super().get_context_data(**kwargs) @@ -5613,11 +5313,9 @@ class EstimatePreviewView(LoginRequiredMixin, PermissionRequiredMixin, DetailVie estimate = kwargs.get("object") if estimate.get_itemtxs_data(): - # data = get_financial_values(estimate) # calculator = CarFinanceCalculator(estimate) kwargs["data"] = get_finance_data(estimate,self.request.dealer) - kwargs["data"] = get_finance_data(estimate,self.request.dealer) return super().get_context_data(**kwargs) @@ -5757,10 +5455,8 @@ class InvoiceListView(LoginRequiredMixin, PermissionRequiredMixin, ListView): ] ): qs = models.ExtraInfo.get_invoices(staff=staff, is_dealer=True,dealer=dealer) - qs = models.ExtraInfo.get_invoices(staff=staff, is_dealer=True,dealer=dealer) elif self.request.is_staff: qs = models.ExtraInfo.get_invoices(staff=staff,dealer=dealer) - qs = models.ExtraInfo.get_invoices(staff=staff,dealer=dealer) except Exception as e: print(e) @@ -5802,7 +5498,6 @@ class InvoiceDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView) # calculator = CarFinanceCalculator(invoice) # finance_data = calculator.get_finance_data() finance_data = get_finance_data(invoice,self.request.dealer) - finance_data = get_finance_data(invoice,self.request.dealer) kwargs["data"] = finance_data kwargs["payments"] = JournalEntryModel.objects.filter( ledger=invoice.ledger @@ -5899,7 +5594,6 @@ class ApprovedInvoiceModelUpdateFormView( return reverse_lazy( "invoice_detail", kwargs={"dealer_slug": self.kwargs["dealer_slug"],"entity_slug": self.kwargs["entity_slug"], "pk": self.object.pk}, - kwargs={"dealer_slug": self.kwargs["dealer_slug"],"entity_slug": self.kwargs["entity_slug"], "pk": self.object.pk}, ) @@ -5948,7 +5642,6 @@ class PaidInvoiceModelUpdateFormView( return reverse_lazy( "invoice_detail", kwargs={"dealer_slug": self.kwargs["dealer_slug"],"entity_slug": self.kwargs["entity_slug"], "pk": self.object.pk}, - kwargs={"dealer_slug": self.kwargs["dealer_slug"],"entity_slug": self.kwargs["entity_slug"], "pk": self.object.pk}, ) def form_valid(self, form): @@ -5957,7 +5650,6 @@ class PaidInvoiceModelUpdateFormView( if invoice.get_amount_open() > 0: messages.error(self.request, "Invoice is not fully paid") return redirect("invoice_detail",dealer_slug=self.kwargs["dealer_slug"],entity_slug=self.kwargs["entity_slug"], pk=invoice.pk) - return redirect("invoice_detail",dealer_slug=self.kwargs["dealer_slug"],entity_slug=self.kwargs["entity_slug"], pk=invoice.pk) else: invoice.post_ledger() invoice.save() @@ -5990,13 +5682,11 @@ def invoice_mark_as(request, dealer_slug, pk): if not invoice.can_approve(): messages.error(request, "invoice is not ready for approval") return redirect("invoice_detail", dealer_slug=dealer_slug,entity_slug=request.entity.slug, pk=invoice.pk) - return redirect("invoice_detail", dealer_slug=dealer_slug,entity_slug=request.entity.slug, pk=invoice.pk) invoice.mark_as_approved( entity_slug=dealer.entity.slug, user_model=dealer.entity.admin ) invoice.save() return redirect("invoice_detail", dealer_slug=dealer_slug,entity_slug=request.entity.slug, pk=invoice.pk) - return redirect("invoice_detail", dealer_slug=dealer_slug,entity_slug=request.entity.slug, pk=invoice.pk) @login_required @@ -6036,7 +5726,6 @@ def invoice_create(request, dealer_slug, pk): # calculator = CarFinanceCalculator(estimate) # finance_data = calculator.get_finance_data() - finance_data = get_finance_data(estimate,dealer) finance_data = get_finance_data(estimate,dealer) car = finance_data.get("car") invoice_itemtxs = { @@ -6062,7 +5751,6 @@ def invoice_create(request, dealer_slug, pk): invoice.save() messages.success(request, "Invoice created successfully") return redirect("invoice_detail", dealer_slug=dealer.slug,entity_slug=entity.slug, pk=invoice.pk) - return redirect("invoice_detail", dealer_slug=dealer.slug,entity_slug=entity.slug, pk=invoice.pk) else: print(form.errors) form = forms.InvoiceModelCreateForm( @@ -6115,7 +5803,6 @@ class InvoicePreviewView(LoginRequiredMixin, PermissionRequiredMixin, DetailView if invoice.get_itemtxs_data(): # calculator = CarFinanceCalculator(invoice) finance_data = get_finance_data(invoice,dealer) - finance_data = get_finance_data(invoice,dealer) kwargs["data"] = finance_data kwargs["dealer"] = dealer return super().get_context_data(**kwargs) @@ -6124,7 +5811,6 @@ class InvoicePreviewView(LoginRequiredMixin, PermissionRequiredMixin, DetailView # payments class InvoiceModelUpdateView(InvoiceModelUpdateViewBase): - template_name = 'sales/invoices/invoice_update.html' template_name = 'sales/invoices/invoice_update.html' permission_required = ["django_ledger.change_invoicemodel"] @@ -6198,7 +5884,6 @@ def PaymentCreateView(request, dealer_slug, pk): # bill = form.cleaned_data.get("bill") payment_method = form.cleaned_data.get("payment_method") response = redirect("invoice_detail", dealer_slug=dealer.slug,entity_slug=entity.slug, pk=model.pk)# if invoice else "bill_detail" - response = redirect("invoice_detail", dealer_slug=dealer.slug,entity_slug=entity.slug, pk=model.pk)# if invoice else "bill_detail" # model = invoice if invoice else bill if not model.is_approved(): @@ -6376,7 +6061,6 @@ def payment_mark_as_paid(request, dealer_slug, pk): ) messages.error(request, f"Error: {str(e)}") return redirect("invoice_detail", dealer_slug=dealer_slug,entity_slug=request.entity.slug, pk=invoice.pk) - return redirect("invoice_detail", dealer_slug=dealer_slug,entity_slug=request.entity.slug, pk=invoice.pk) # activity log @@ -6583,8 +6267,6 @@ def lead_create(request, dealer_slug): customer = models.Customer.objects.filter( dealer=dealer, email=instance.email - dealer=dealer, - email=instance.email ).first() if not customer: customer = models.Customer( @@ -6605,8 +6287,6 @@ def lead_create(request, dealer_slug): organization = models.Organization.objects.filter( dealer=dealer, email=instance.email - dealer=dealer, - email=instance.email ).first() if not organization: organization = models.Organization( @@ -6628,7 +6308,6 @@ def lead_create(request, dealer_slug): ) messages.success(request, _("Lead created successfully")) return redirect("lead_detail",dealer_slug=dealer_slug,slug=instance.slug) - else: logger.error( f"error creating leading for dealer {dealer_slug} by user:{user_username}" @@ -6656,6 +6335,7 @@ def lead_create(request, dealer_slug): qs = form.fields["id_car_make"].queryset.filter( is_sa_import=True, pk__in=dealer_make_list ) + # print(qs) form.fields["staff"].queryset = ( form.fields["staff"] .queryset.select_related("user") @@ -6674,6 +6354,7 @@ def lead_create(request, dealer_slug): form.fields["staff"].queryset = models.Staff.objects.filter( dealer=dealer, pk=request.staff.pk ) + qs = qs.order_by("name") form.fields["id_car_make"].queryset = qs form.fields["id_car_make"].choices = [ (obj.id_car_make, obj.get_local_name()) for obj in qs @@ -6700,7 +6381,6 @@ def lead_tracking(request, dealer_slug): else: qs = models.Lead.objects.filter(dealer=dealer) leads=qs - leads=qs won = qs.filter(status="won") new = qs.filter(status="new") lose = qs.filter(status="lose") @@ -6714,7 +6394,6 @@ def lead_tracking(request, dealer_slug): "lose": lose, "negotiation": negotiation, "leads":leads - "leads":leads } return render(request, "crm/leads/lead_tracking.html", context) @@ -6749,10 +6428,6 @@ def update_lead_actions(request, dealer_slug): request, _("All fields are required") ) - messages.error( - request, - _("All fields are required") - ) return redirect("lead_detail", dealer_slug=dealer_slug, slug=lead.slug) # return JsonResponse( # {"success": False, "message": "All fields are required"}, status=400 @@ -6761,7 +6436,6 @@ def update_lead_actions(request, dealer_slug): # Get the lead - # Update lead fields lead.status = current_action @@ -6794,10 +6468,6 @@ def update_lead_actions(request, dealer_slug): request, _("Invalid date format") ) - messages.error( - request, - _("Invalid date format") - ) return redirect("lead_detail", dealer_slug=dealer_slug, slug=lead.slug) # return JsonResponse( # {"success": False, "message": "Invalid date format"}, status=400 @@ -6813,10 +6483,6 @@ def update_lead_actions(request, dealer_slug): request, _("Actions updated successfully") ) - messages.success( - request, - _("Actions updated successfully") - ) return redirect("lead_detail", dealer_slug=dealer_slug, slug=lead.slug) # return JsonResponse( # {"success": True, "message": "Actions updated successfully"} @@ -6832,10 +6498,6 @@ def update_lead_actions(request, dealer_slug): request, _("Lead not found") ) - messages.error( - request, - _("Lead not found") - ) return redirect("lead_detail", dealer_slug=dealer_slug, slug=lead.slug) # return JsonResponse({"success": False, "message": "Lead not found"}, status=404) except Exception as e: @@ -6849,42 +6511,10 @@ def update_lead_actions(request, dealer_slug): request, _("An error occurred while updating lead actions") ) - messages.error( - request, - _("An error occurred while updating lead actions") - ) return redirect("lead_detail", dealer_slug=dealer_slug, slug=lead.slug) # return JsonResponse({"success": False, "message": str(e)}, status=500) - -def lead_update(request,dealer_slug,slug): - dealer = get_object_or_404(models.Dealer, slug=dealer_slug) - lead = get_object_or_404(models.Lead, slug=slug) - form = forms.LeadForm(instance=lead) - if "HX-Request" in request.headers: - make_id = request.GET.get("id_car_make") - make = models.CarMake.objects.get(pk=make_id) - form.fields[ - "id_car_model" - ].queryset = make.carmodel_set.all() - else: - form.fields[ - "id_car_model" - ].queryset = form.instance.id_car_make.carmodel_set.all() - form.fields["staff"].queryset = ( - form.fields["staff"] - .queryset.select_related("user") - .filter( - dealer=dealer, - user__groups__permissions__codename__contains="add_lead", - ) - .distinct() - ) - context = { - "form":form - } - return render(request,"crm/leads/lead_form.html",context) class LeadUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView): """ Handles the update view for Lead objects. @@ -7174,7 +6804,6 @@ def schedule_event(request, dealer_slug, content_type, slug): form = forms.ScheduleForm(request.POST) if form.is_valid(): - reminder = form.cleaned_data['reminder'] reminder = form.cleaned_data['reminder'] instance = form.save(commit=False) instance.dealer = dealer @@ -7224,7 +6853,6 @@ def schedule_event(request, dealer_slug, content_type, slug): ) if reminder: scheduled_at_aware = timezone.make_aware(instance.scheduled_at, timezone.get_current_timezone()) if timezone.is_naive(instance.scheduled_at) else instance.scheduled_at - scheduled_at_aware = timezone.make_aware(instance.scheduled_at, timezone.get_current_timezone()) if timezone.is_naive(instance.scheduled_at) else instance.scheduled_at reminder_time = scheduled_at_aware - timezone.timedelta(minutes=15) # Only schedule if the reminder time is in the future @@ -7233,17 +6861,14 @@ def schedule_event(request, dealer_slug, content_type, slug): DjangoQSchedule.objects.create( name=f"send_schedule_reminder_email_to_{instance.scheduled_by.email}_for_{content_type}_with_PK_{instance.pk}", func='inventory.tasks.send_schedule_reminder_email', - func='inventory.tasks.send_schedule_reminder_email', args=f'"{instance.pk}"', schedule_type=DjangoQSchedule.ONCE, next_run=reminder_time, hook='inventory.tasks.log_email_status', - hook='inventory.tasks.log_email_status', ) messages.success(request, _("Appointment Created Successfully")) return redirect(f'{content_type}_detail',dealer_slug=dealer_slug, slug=slug) - return redirect(f'{content_type}_detail',dealer_slug=dealer_slug, slug=slug) else: # Log for invalid form data @@ -7284,7 +6909,6 @@ def lead_transfer(request, dealer_slug, slug): else: messages.error(request, f"Invalid form data: {str(form.errors)}") return redirect("lead_detail", dealer_slug=dealer.slug ,slug=lead.slug) - return redirect("lead_detail", dealer_slug=dealer.slug ,slug=lead.slug) @login_required @@ -7371,7 +6995,6 @@ def send_lead_email(request, dealer_slug, slug, email_pk=None): # ) # return response # return redirect("lead_list", dealer_slug=dealer.slug) - # return redirect("lead_list", dealer_slug=dealer.slug) if request.method == "POST": email_pk = request.POST.get("email_pk") @@ -7427,7 +7050,6 @@ def send_lead_email(request, dealer_slug, slug, email_pk=None): # ) # return response # return redirect("lead_list", dealer_slug=dealer_slug) - # return redirect("lead_list", dealer_slug=dealer_slug) msg = f""" السلام عليكم {lead.full_name}, @@ -7529,9 +7151,6 @@ class OpportunityCreateView( form.fields["lead"].queryset = models.Lead.objects.filter( dealer=dealer ) - form.fields["lead"].queryset = models.Lead.objects.filter( - dealer=dealer - ) elif self.request.is_staff: form.fields["lead"].queryset = models.Lead.objects.filter( dealer=dealer, staff=self.request.staff @@ -7580,14 +7199,12 @@ class OpportunityUpdateView( permission_required = ["inventory.change_opportunity"] - def get_form(self, form_class=None): form = super().get_form(form_class) dealer = get_object_or_404(models.Dealer, slug=self.kwargs.get("dealer_slug")) staff = getattr(self.request.user, "staff", None) form.fields["car"].queryset = models.Car.objects.filter( dealer=dealer, status="available",marked_price__gt=0 - dealer=dealer, status="available",marked_price__gt=0 ) form.fields["lead"].queryset = models.Lead.objects.filter( dealer=dealer, staff=staff @@ -7634,7 +7251,6 @@ class OpportunityStageUpdateView( permission_required = ["inventory.change_opportunity"] - def get_success_url(self): return reverse_lazy( "opportunity_detail", @@ -7760,9 +7376,6 @@ class OpportunityListView(LoginRequiredMixin, PermissionRequiredMixin, ListView) queryset = models.Opportunity.objects.filter(dealer=dealer, lead__staff=staff) - queryset = models.Opportunity.objects.filter(dealer=dealer, lead__staff=staff) - - # Stage filter stage = self.request.GET.get("stage") @@ -7780,7 +7393,6 @@ class OpportunityListView(LoginRequiredMixin, PermissionRequiredMixin, ListView) queryset = queryset.order_by("expected_close_date") # Search filter - # Search filter search = self.request.GET.get("q") if search: queryset = queryset.filter( @@ -8039,18 +7651,11 @@ class ItemServiceListView(LoginRequiredMixin, PermissionRequiredMixin, ListView) Q(id__icontains=query)| Q(uom__icontains=query) ) - qs = qs.filter(Q(name__icontains=query)| - Q(id__icontains=query)| - Q(uom__icontains=query) - ) return qs -class ItemExpenseCreateView(LoginRequiredMixin, PermissionRequiredMixin,SuccessMessageMixin, CreateView): - - class ItemExpenseCreateView(LoginRequiredMixin, PermissionRequiredMixin,SuccessMessageMixin, CreateView): """ Represents a view for creating item expense entries. @@ -8145,9 +7750,6 @@ class ItemExpenseUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateV - - - class ItemExpenseListView(LoginRequiredMixin, PermissionRequiredMixin, ListView): """ Handles the display of a list of item expenses. @@ -8216,8 +7818,6 @@ class BillListView(LoginRequiredMixin, PermissionRequiredMixin, ListView): if query: qs = qs.filter(Q(bill_number__icontains=query)| Q(vendor__vendor_name__icontains=query)) - qs = qs.filter(Q(bill_number__icontains=query)| - Q(vendor__vendor_name__icontains=query)) return qs def get_context_data(self, **kwargs): @@ -8226,7 +7826,6 @@ class BillListView(LoginRequiredMixin, PermissionRequiredMixin, ListView): return context -class BillModelCreateView(LoginRequiredMixin, PermissionRequiredMixin,SuccessMessageMixin, CreateView): class BillModelCreateView(LoginRequiredMixin, PermissionRequiredMixin,SuccessMessageMixin, CreateView): template_name = "bill/bill_create.html" PAGE_TITLE = _("Create Bill") @@ -8846,7 +8445,7 @@ class FiscalYearIncomeStatementViewBase( """ template_name = "ledger/reports/income_statement.html" - permission_required = ["inventory.view_carfinance"] + permission_required = ["django_ledger.view_ledgermodel"] def get_login_url(self): return reverse("account_login") @@ -8985,7 +8584,7 @@ class FiscalYearCashFlowStatementViewBase( """ template_name = "ledger/reports/cash_flow_statement.html" - permission_required = ["inventory.view_carfinance"] + permission_required = ["django_ledger.view_ledgermodel"] def get_login_url(self): return reverse("account_login") @@ -9174,7 +8773,7 @@ class FiscalYearEntityModelDashboardView( :type permission_required: list """ - permission_required = ["inventory.view_carfinance"] + permission_required = ["django_ledger.view_ledgermodel"] def get_login_url(self): return reverse("account_login") @@ -9566,7 +9165,6 @@ def schedule_cancel(request, dealer_slug, pk): @permission_required("inventory.change_dealer", raise_exception=True) def assign_car_makes(request, dealer_slug): - """ Assigns car makes to a dealer. @@ -9694,7 +9292,6 @@ class LedgerModelDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailV permission_required = "django_ledger.view_ledgermodel" -class LedgerModelCreateView(LedgerModelCreateViewBase,SuccessMessageMixin): class LedgerModelCreateView(LedgerModelCreateViewBase,SuccessMessageMixin): """ Handles the creation of LedgerModel entities. @@ -9760,10 +9357,8 @@ class LedgerModelModelActionView(LedgerModelModelActionViewBase): - @login_required @permission_required("django_ledger.delete_ledgermodel", raise_exception=True) -def LedgerModelDeleteView(request, dealer_slug,entity_slug,ledger_pk): def LedgerModelDeleteView(request, dealer_slug,entity_slug,ledger_pk): ledger = LedgerModel.objects.filter(pk=ledger_pk).first() if request.method == "POST": @@ -9771,7 +9366,6 @@ def LedgerModelDeleteView(request, dealer_slug,entity_slug,ledger_pk): messages.success(request, _("Ledger deleted successfully")) return redirect("ledger_list", dealer_slug=dealer_slug, entity_slug=entity_slug) return render(request,"ledger/ledger/ledger_delete.html",{"ledger_model":ledger}) - return render(request,"ledger/ledger/ledger_delete.html",{"ledger_model":ledger}) # class LedgerModelDeleteView(DeleteView, SuccessMessageMixin): # """ # Handles the deletion of a Ledger model instance. @@ -9896,7 +9490,6 @@ class JournalEntryCreateView( @login_required @permission_required("django_ledger.delete_journalentrymodel", raise_exception=True) -def JournalEntryDeleteView(request,dealer_slug, pk): def JournalEntryDeleteView(request,dealer_slug, pk): """ Handles the deletion of a specific journal entry. This view facilitates @@ -9919,11 +9512,9 @@ def JournalEntryDeleteView(request,dealer_slug, pk): if not journal_entry.can_delete(): messages.error(request, _("Journal Entry cannot be deleted")) return redirect("journalentry_list",dealer_slug=dealer_slug, pk=ledger.pk) - return redirect("journalentry_list",dealer_slug=dealer_slug, pk=ledger.pk) journal_entry.delete() messages.success(request, "Journal Entry deleted") return redirect("journalentry_list",dealer_slug=dealer_slug, pk=ledger.pk) - return redirect("journalentry_list",dealer_slug=dealer_slug, pk=ledger.pk) return render( request, "ledger/journal_entry/journal_entry_delete.html", @@ -10112,22 +9703,15 @@ def ledger_unpost_all_journals(request, dealer_slug, entity_slug, pk): @login_required @permission_required("inventory.change_dealer", raise_exception=True) def pricing_page(request, dealer_slug): - dealer=get_object_or_404(models.Dealer, slug=dealer_slug) dealer=get_object_or_404(models.Dealer, slug=dealer_slug) if not dealer.active_plan: plan_list = PlanPricing.objects.all() form = forms.PaymentPlanForm() return render(request, "pricing_page.html", {"plan_list": plan_list, "form": form}) - plan_list = PlanPricing.objects.all() - form = forms.PaymentPlanForm() - return render(request, "pricing_page.html", {"plan_list": plan_list, "form": form}) else: messages.info(request,_("You already have an plan!!")) return redirect('home',dealer_slug=dealer_slug) - messages.info(request,_("You already have an plan!!")) - return redirect('home',dealer_slug=dealer_slug) - @login_required @@ -10168,13 +9752,11 @@ def payment_callback(request, dealer_slug): history = models.PaymentHistory.objects.filter(transaction_id=payment_id).first() payment_status = request.GET.get("status") logger.info(f"Received payment callback for dealer_slug: {dealer_slug}, payment_id: {payment_id}, status: {payment_status}") - logger.info(f"Received payment callback for dealer_slug: {dealer_slug}, payment_id: {payment_id}, status: {payment_status}") order = Order.objects.filter(user=dealer.user, status=1).first() # Status 1 = NEW print(order) if payment_status == "paid": logger.info(f"Payment successful for transaction ID {payment_id}. Processing order completion.") - logger.info(f"Payment successful for transaction ID {payment_id}. Processing order completion.") billing_info, created = BillingInfo.objects.get_or_create( user=dealer.user, @@ -10186,35 +9768,24 @@ def payment_callback(request, dealer_slug): 'city': dealer.entity.city or " ", 'country': dealer.entity.country or " ", } - 'tax_number': dealer.vrn, - 'name': dealer.arabic_name, - 'street': dealer.address, - 'zipcode': dealer.entity.zip_code or " ", - 'city': dealer.entity.city or " ", - 'country': dealer.entity.country or " ", - } ) if created: logger.info(f"Created new billing info for user {dealer.user}.") else: logger.debug(f"Billing info already exists for user {dealer.user}.") - if not hasattr(order.user, 'userplan'): if not hasattr(order.user, 'userplan'): UserPlan.objects.create( user=order.user, plan=order.plan, expire=datetime.now().date() + timedelta(days=order.get_plan_pricing().pricing.period) - expire=datetime.now().date() + timedelta(days=order.get_plan_pricing().pricing.period) ) logger.info(f"Created new UserPlan for user {order.user} with plan {order.plan}.") - logger.info(f"Created new UserPlan for user {order.user} with plan {order.plan}.") else: logger.info(f"UserPlan already exists for user {order.user}.") try: - # if order.user.userplan: # user = order.user # pricing = order.get_plan_pricing().pricing @@ -10230,28 +9801,21 @@ def payment_callback(request, dealer_slug): history.status = "paid" history.save() logger.info(f"Order {order.id} for user {order.user} completed successfully. Payment history updated.") - logger.info(f"Order {order.id} for user {order.user} completed successfully. Payment history updated.") invoice = order.get_invoices().first() return render( request, "payment_success.html", {"order": order, "invoice": invoice} - request, - "payment_success.html", - {"order": order, "invoice": invoice} ) except Exception as e: - logger.exception(f"Error completing order {order.id} for user {order.user}: {e}") logger.exception(f"Error completing order {order.id} for user {order.user}: {e}") logger.error(f"Plan activation failed: {str(e)}") history.status = "failed" history.save() return render(request, "payment_failed.html", {"message": "Plan activation error"}) - return render(request, "payment_failed.html", {"message": "Plan activation error"}) elif payment_status == "failed": - logger.warning(f"Payment failed for transaction ID {payment_id}. Message: {message}") logger.warning(f"Payment failed for transaction ID {payment_id}. Message: {message}") history.status = "failed" history.save() @@ -10479,7 +10043,6 @@ def add_task(request, dealer_slug, content_type, slug): - @login_required @permission_required("inventory.change_tasks", raise_exception=True) def update_task(request, dealer_slug, pk): @@ -10597,10 +10160,6 @@ def user_management(request, dealer_slug): "organizations": models.Organization.objects.filter(active=False,dealer=dealer), "vendors": models.Vendor.objects.filter(active=False,dealer=dealer), "staff": models.Staff.objects.filter(active=False,dealer=dealer), - "customers": models.Customer.objects.filter(active=False,dealer=dealer), - "organizations": models.Organization.objects.filter(active=False,dealer=dealer), - "vendors": models.Vendor.objects.filter(active=False,dealer=dealer), - "staff": models.Staff.objects.filter(active=False,dealer=dealer), } return render(request, "admin_management/user_management.html", context) @@ -11041,7 +10600,6 @@ class PurchaseOrderDetailView(LoginRequiredMixin, PermissionRequiredMixin, Detai context["page_title"] = title context["header_title"] = title context["po_ready_to_fulfill"] = all([item for item in po_model.get_itemtxs_data()[0] if item.po_item_status == 'received']) - context["po_ready_to_fulfill"] = all([item for item in po_model.get_itemtxs_data()[0] if item.po_item_status == 'received']) po_model: PurchaseOrderModel = self.object po_items_qs, item_data = po_model.get_itemtxs_data( queryset=po_model.itemtransactionmodel_set.all().select_related( @@ -11069,7 +10627,6 @@ class PurchaseOrderListView(LoginRequiredMixin, PermissionRequiredMixin, ListVie query = self.request.GET.get("q") qs = self.model.objects.filter(entity=dealer.entity) if query: - qs=qs.filter(Q(po_number__icontains=query)|Q(po_status__icontains=query)|Q(po_title__icontains=query)) qs=qs.filter(Q(po_number__icontains=query)|Q(po_status__icontains=query)|Q(po_title__icontains=query)) return qs return qs @@ -11078,7 +10635,6 @@ class PurchaseOrderListView(LoginRequiredMixin, PermissionRequiredMixin, ListVie context = super().get_context_data(**kwargs) dealer = get_user_type(self.request) vendors=models.Vendor.objects.filter(dealer=dealer) - vendors=models.Vendor.objects.filter(dealer=dealer) context = super().get_context_data(**kwargs) context["entity_slug"] = dealer.entity.slug context["vendors"] = vendors @@ -11217,7 +10773,6 @@ def upload_cars(request, dealer_slug, pk=None): response = redirect("upload_cars", dealer_slug=dealer_slug, pk=pk) if po_item.status == "uploaded": - messages.add_message(request, messages.SUCCESS, "Item uploaded Sucessfully.") messages.add_message(request, messages.SUCCESS, "Item uploaded Sucessfully.") return redirect( "view_items_inventory", @@ -11354,12 +10909,6 @@ def upload_cars(request, dealer_slug, pk=None): # marked_price=0, # selling_price=0, # ) - # models.CarFinance.objects.create( - # car=car, - # cost_price=po_item.item.unit_cost, - # marked_price=0, - # selling_price=0, - # ) car.add_colors(exterior=exterior, interior=interior) cars_created += 1 logger.debug( @@ -11445,32 +10994,20 @@ class InventoryListView(InventoryListViewBase): permission_required = ["django_ledger.view_purchaseordermodel"] @login_required -def purchase_report_view(request,dealer_slug): def purchase_report_view(request,dealer_slug): pos = request.entity.get_purchase_orders() data = [] total_po_amount=0 total_po_cars=0 - total_po_amount=0 - total_po_cars=0 for po in pos: items = [{"total":x.total_amount,"q":x.quantity} for x in po.get_itemtxs_data()[0].all()] - items = [{"total":x.total_amount,"q":x.quantity} for x in po.get_itemtxs_data()[0].all()] - po_amount=0 - po_quantity=0 po_amount=0 po_quantity=0 for item in items: po_amount+=item["total"] po_quantity+=item["q"] - po_amount+=item["total"] - po_quantity+=item["q"] - total_po_amount+=po_amount - total_po_cars+=po_quantity - bills=po.get_po_bill_queryset() - vendors=set([bill.vendor.vendor_name for bill in bills]) total_po_amount+=po_amount total_po_cars+=po_quantity bills=po.get_po_bill_queryset() @@ -11478,8 +11015,6 @@ def purchase_report_view(request,dealer_slug): vendors_str = ", ".join(sorted(list(vendors))) if vendors else "N/A" data.append({"po_number":po.po_number,"po_created":po.created,"po_status":po.po_status,"po_fulfilled_date":po.date_fulfilled,"po_amount":po_amount, "po_quantity":po_quantity,"vendors_str":vendors_str}) - data.append({"po_number":po.po_number,"po_created":po.created,"po_status":po.po_status,"po_fulfilled_date":po.date_fulfilled,"po_amount":po_amount, - "po_quantity":po_quantity,"vendors_str":vendors_str}) current_time = timezone.now().strftime("%Y-%m-%d %H:%M:%S") context={ @@ -11490,27 +11025,13 @@ def purchase_report_view(request,dealer_slug): "total_po_cars":total_po_cars, "current_time":current_time - context={ - "dealer":request.entity.name, - "time":current_time, - "data":data, - "total_po_amount":total_po_amount, - "total_po_cars":total_po_cars, - "current_time":current_time - } - - - return render(request,'ledger/reports/purchase_report.html',context) return render(request,'ledger/reports/purchase_report.html',context) -def purchase_report_csv_export(request,dealer_slug): - response = HttpResponse(content_type='text/csv') - def purchase_report_csv_export(request,dealer_slug): response = HttpResponse(content_type='text/csv') @@ -11518,12 +11039,10 @@ def purchase_report_csv_export(request,dealer_slug): current_time = timezone.now().strftime("%Y-%m-%d_%H%M%S") filename = f"purchase_report_{dealer_slug}_{current_time}.csv" response['Content-Disposition'] = f'attachment; filename="{filename}"' - response['Content-Disposition'] = f'attachment; filename="{filename}"' writer = csv.writer(response) - header = [ 'PO Number', 'Created Date', @@ -11532,13 +11051,6 @@ def purchase_report_csv_export(request,dealer_slug): 'PO Amount', 'PO Quantity', 'Vendors' - 'PO Number', - 'Created Date', - 'Status', - 'Fulfilled Date', - 'PO Amount', - 'PO Quantity', - 'Vendors' ] writer.writerow(header) pos = request.entity.get_purchase_orders() @@ -11547,7 +11059,6 @@ def purchase_report_csv_export(request,dealer_slug): po_amount = 0 po_quantity = 0 items = [{"total":x.total_amount,"q":x.quantity} for x in po.get_itemtxs_data()[0].all()] - items = [{"total":x.total_amount,"q":x.quantity} for x in po.get_itemtxs_data()[0].all()] for item in items: po_amount += item["total"] @@ -11555,20 +11066,9 @@ def purchase_report_csv_export(request,dealer_slug): bills = po.get_po_bill_queryset() vendors = set([bill.vendor.vendor_name for bill in bills ]) - vendors = set([bill.vendor.vendor_name for bill in bills ]) vendors_str = ", ".join(sorted(list(vendors))) if vendors else "N/A" - writer.writerow([ - po.po_number, - po.created.strftime("%Y-%m-%d %H:%M:%S") if po.created else '', - po.get_po_status_display(), - po.date_fulfilled.strftime("%Y-%m-%d") if po.date_fulfilled else '', - f"{po_amount:.2f}", - po_quantity, - vendors_str - ]) - writer.writerow([ po.po_number, po.created.strftime("%Y-%m-%d %H:%M:%S") if po.created else '', @@ -11582,16 +11082,11 @@ def purchase_report_csv_export(request,dealer_slug): - @login_required def car_sale_report_view(request, dealer_slug): dealer = get_object_or_404(models.Dealer, slug=dealer_slug) vat = models.VatRate.objects.filter(dealer=dealer,is_active=True).first() VAT_RATE=vat.rate - vat = models.VatRate.objects.filter(dealer=dealer,is_active=True).first() - VAT_RATE=vat.rate - - cars_sold = models.Car.objects.filter(dealer=dealer, status='sold') cars_sold = models.Car.objects.filter(dealer=dealer, status='sold') @@ -11602,11 +11097,6 @@ def car_sale_report_view(request, dealer_slug): selected_serie = request.GET.get('serie') selected_year = request.GET.get('year') selected_stock_type=request.GET.get('stock_type') - selected_make = request.GET.get('make') - selected_model = request.GET.get('model') - selected_serie = request.GET.get('serie') - selected_year = request.GET.get('year') - selected_stock_type=request.GET.get('stock_type') # Apply filters to the queryset if selected_make: @@ -11621,28 +11111,16 @@ def car_sale_report_view(request, dealer_slug): cars_sold = cars_sold.filter(stock_type=selected_stock_type) - # # Calculate summary data for the filtered results total_cars_sold=cars_sold.count() total_revenue_from_cars = cars_sold.aggregate( total=Sum(F('marked_price') - F('discount_amount')) )['total'] or 0 - total_cars_sold=cars_sold.count() - total_revenue_from_cars = cars_sold.aggregate( - total=Sum(F('marked_price') - F('discount_amount')) - )['total'] or 0 - total_vat_on_cars=cars_sold.annotate( - final_price=F('marked_price') - F('discount_amount')).aggregate( - total=Sum(F('final_price') * VAT_RATE))['total'] or 0 total_vat_on_cars=cars_sold.annotate( final_price=F('marked_price') - F('discount_amount')).aggregate( total=Sum(F('final_price') * VAT_RATE))['total'] or 0 - 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]) - total_vat_collected = total_vat_on_cars+total_vat_from_additonals - total_revenue_collected=total_revenue_from_cars+total_revenue_from_additonals 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]) total_vat_collected = total_vat_on_cars+total_vat_from_additonals @@ -11655,13 +11133,7 @@ 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() - 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') 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') @@ -11688,41 +11160,17 @@ def car_sale_report_view(request, dealer_slug): 'selected_serie': selected_serie, 'selected_year': selected_year, 'selected_stock_type':selected_stock_type, - 'cars_sold': cars_sold, - 'total_cars_sold':total_cars_sold, - 'current_time': current_time, - 'dealer': dealer, - 'total_revenue_from_cars': total_revenue_from_cars, - 'total_revenue_from_additonals':total_revenue_from_additonals, - 'total_revenue_collected': total_revenue_collected, - 'total_vat_on_cars':total_vat_on_cars, - 'total_vat_from_additonals':total_vat_from_additonals, - 'total_vat_collected':total_vat_collected, - 'total_discount': total_discount, - 'makes': makes, - 'models': models_qs, - 'series': series, - 'years': years, - 'stock_types':stock_types, - 'selected_make': selected_make, - 'selected_model': selected_model, - 'selected_serie': selected_serie, - 'selected_year': selected_year, - 'selected_stock_type':selected_stock_type, } return render(request, 'ledger/reports/car_sale_report.html', context) - return render(request, 'ledger/reports/car_sale_report.html', context) @login_required def car_sale_report_csv_export(request, dealer_slug): - response = HttpResponse(content_type='text/csv') response = HttpResponse(content_type='text/csv') current_time = timezone.now().strftime("%Y-%m-%d_%H-%M-%S") filename = f"sales_report_{dealer_slug}_{current_time}.csv" response['Content-Disposition'] = f'attachment; filename="{filename}"' - response['Content-Disposition'] = f'attachment; filename="{filename}"' writer = csv.writer(response) @@ -11733,17 +11181,11 @@ def car_sale_report_csv_export(request, dealer_slug): 'Marked Price', 'Discount Amount', 'Selling Price', 'VAT on Car', 'Services Price', 'VAT on Services', 'Final Total', 'Invoice Number' - 'VIN', 'Make', 'Model', 'Year', 'Serie', 'Trim', 'Mileage', - 'Stock Type', 'Created Date', 'Sold Date', 'Cost Price', - 'Marked Price', 'Discount Amount', 'Selling Price', - 'VAT on Car', 'Services Price', 'VAT on Services', 'Final Total', - 'Invoice Number' ] writer.writerow(header) dealer = get_object_or_404(models.Dealer, slug=dealer_slug) cars_sold = models.Car.objects.filter(dealer=dealer, status='sold') - cars_sold = models.Car.objects.filter(dealer=dealer, status='sold') # Apply filters from the request, just like in your HTML view selected_make = request.GET.get('make') @@ -11751,11 +11193,6 @@ def car_sale_report_csv_export(request, dealer_slug): selected_serie = request.GET.get('serie') selected_year = request.GET.get('year') selected_stock_type = request.GET.get('stock_type') - selected_make = request.GET.get('make') - selected_model = request.GET.get('model') - selected_serie = request.GET.get('serie') - selected_year = request.GET.get('year') - selected_stock_type = request.GET.get('stock_type') if selected_make: cars_sold = cars_sold.filter(id_car_make__name=selected_make) @@ -11774,8 +11211,6 @@ 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'] - 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 @@ -11805,27 +11240,6 @@ def car_sale_report_csv_export(request, dealer_slug): car.final_price_plus_services_plus_vat, invoice_number, ]) - writer.writerow([ - car.vin, - car.id_car_make.name, - car.id_car_model.name, - car.year, - car.id_car_serie.name, - car.id_car_trim.name, - car.mileage if car.mileage else '0', - car.stock_type, - car.created_at.strftime("%Y-%m-%d %H:%M:%S") if car.created_at else '', - sold_date.strftime("%Y-%m-%d %H:%M:%S") if sold_date else '', - car.cost_price, - car.marked_price, - car.discount, # Ensure this property returns a number - car.final_price, # Selling Price without VAT - car.vat_amount, # VAT on the car - services_total_price, # Total services without VAT - services_vat_amount, # VAT on services - car.final_price_plus_services_plus_vat, - invoice_number, - ]) return response @@ -11836,66 +11250,45 @@ def staff_password_reset_view(request, dealer_slug, user_pk): dealer = get_object_or_404(models.Dealer, slug=dealer_slug) staff = models.Staff.objects.filter(dealer=dealer, pk=user_pk).first() - if request.method == 'POST': if request.method == 'POST': form = forms.CustomSetPasswordForm(staff.user, request.POST) if form.is_valid(): form.save() messages.success(request, _('Your password has been set. You may go ahead and log in now.')) return redirect('user_detail',dealer_slug=dealer_slug,slug=staff.slug) - messages.success(request, _('Your password has been set. You may go ahead and log in now.')) - return redirect('user_detail',dealer_slug=dealer_slug,slug=staff.slug) else: messages.error(request, _('Invalid password. Please try again.')) - messages.error(request, _('Invalid password. Please try again.')) form = forms.CustomSetPasswordForm(staff.user) return render(request, 'users/user_password_reset.html', {'form': form}) - return render(request, 'users/user_password_reset.html', {'form': form}) class RecallListView(ListView): model = models.Recall template_name = 'recalls/recall_list.html' context_object_name = 'recalls' - template_name = 'recalls/recall_list.html' - context_object_name = 'recalls' paginate_by = 20 def get_queryset(self): - queryset = super().get_queryset().annotate( - dealer_count=Count('notifications', distinct=True), - car_count=Count('notifications__cars_affected', distinct=True) queryset = super().get_queryset().annotate( dealer_count=Count('notifications', distinct=True), car_count=Count('notifications__cars_affected', distinct=True) ) return queryset.select_related('make', 'model', 'serie', 'trim') - return queryset.select_related('make', 'model', 'serie', 'trim') class RecallDetailView(DetailView): model = models.Recall template_name = 'recalls/recall_detail.html' context_object_name = 'recall' - template_name = 'recalls/recall_detail.html' - context_object_name = 'recall' def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['notifications'] = self.object.notifications.select_related('dealer') - context['notifications'] = self.object.notifications.select_related('dealer') return context def RecallFilterView(request): - context = {'make_data': models.CarMake.objects.all()} context = {'make_data': models.CarMake.objects.all()} if request.method == "POST": - make = request.POST.get('make') - model = request.POST.get('model') - serie = request.POST.get('serie') - trim = request.POST.get('trim') - year = request.POST.get('year') - url = reverse('recall_create') make = request.POST.get('make') model = request.POST.get('model') serie = request.POST.get('serie') @@ -11907,17 +11300,11 @@ def RecallFilterView(request): context['url'] = url context['cars'] = cars return render(request,'recalls/recall_filter.html',context) - cars = models.Car.objects.filter(id_car_make=make,id_car_model=model,id_car_serie=serie,id_car_trim=trim,year=year) - context['url'] = url - context['cars'] = cars - return render(request,'recalls/recall_filter.html',context) class RecallCreateView(FormView): - template_name = 'recalls/recall_create.html' template_name = 'recalls/recall_create.html' form_class = forms.RecallCreateForm success_url = reverse_lazy('recall_success') - success_url = reverse_lazy('recall_success') def get_form(self, form_class=None): form = super().get_form(form_class) @@ -11926,46 +11313,30 @@ class RecallCreateView(FormView): serie = self.request.GET.get('serie') trim = self.request.GET.get('trim') year = self.request.GET.get('year') - make = self.request.GET.get('make') - model = self.request.GET.get('model') - serie = self.request.GET.get('serie') - trim = self.request.GET.get('trim') - year = self.request.GET.get('year') if make: qs = models.CarMake.objects.filter(pk=make) form.fields['make'].queryset = qs form.initial['make'] = qs.first() - form.fields['make'].queryset = qs - form.initial['make'] = qs.first() if model: qs = models.CarModel.objects.filter(pk=model) form.fields['model'].queryset = qs form.initial['model'] = qs.first() - form.fields['model'].queryset = qs - form.initial['model'] = qs.first() if serie: qs = models.CarSerie.objects.filter(pk=serie) form.fields['serie'].queryset = qs form.initial['serie'] = qs.first() - form.fields['serie'].queryset = qs - form.initial['serie'] = qs.first() if trim: qs = models.CarTrim.objects.filter(pk=trim) form.fields['trim'].queryset = qs form.initial['trim'] = qs.first() - form.fields['trim'].queryset = qs - form.initial['trim'] = qs.first() if year: form.fields['year_from'].initial = year form.fields['year_to'].initial = year - form.fields['year_from'].initial = year - form.fields['year_to'].initial = year return form def get_initial(self): initial = super().get_initial() - if self.request.method == 'GET': if self.request.method == 'GET': initial.update(self.request.GET.dict()) return initial @@ -12004,15 +11375,12 @@ class RecallCreateView(FormView): notification = models.RecallNotification.objects.create( recall=recall, dealer=dealer - recall=recall, - dealer=dealer ) notification.cars_affected.set(dealer_cars) # Send email self.send_notification_email(dealer, recall, dealer_cars) - messages.success(self.request, _("Recall created and notifications sent successfully")) messages.success(self.request, _("Recall created and notifications sent successfully")) return super().form_valid(form) @@ -12023,26 +11391,18 @@ class RecallCreateView(FormView): 'recall': recall, 'cars': cars, }) - message = render_to_string('recalls/email/recall_notification.txt', { - 'dealer': dealer, - 'recall': recall, - 'cars': cars, - }) send_email( subject, message, 'noreply@yourdomain.com', - 'noreply@yourdomain.com', [dealer.user.email], ) class RecallSuccessView(TemplateView): template_name = 'recalls/recall_success.html' - template_name = 'recalls/recall_success.html' @login_required -def schedule_calendar(request,dealer_slug): def schedule_calendar(request,dealer_slug): dealer = get_object_or_404(models.Dealer, slug=dealer_slug) user_schedules = models.Schedule.objects.filter(dealer=dealer,scheduled_by=request.user).order_by('scheduled_at') @@ -12052,31 +11412,19 @@ def schedule_calendar(request,dealer_slug): 'upcoming_schedules':upcoming_schedules } return render(request, 'schedule_calendar.html', context) - user_schedules = models.Schedule.objects.filter(dealer=dealer,scheduled_by=request.user).order_by('scheduled_at') - upcoming_schedules = user_schedules.filter(scheduled_at__gte=timezone.now()).order_by('scheduled_at') - context = { - 'schedules': user_schedules, - 'upcoming_schedules':upcoming_schedules - } - return render(request, 'schedule_calendar.html', context) # Support @login_required def help_center(request): return render(request, 'support/help_center.html') - return render(request, 'support/help_center.html') @login_required @permission_required('inventory.add_ticket') -def create_ticket(request,dealer_slug): -@permission_required('inventory.add_ticket') def create_ticket(request,dealer_slug): if not request.is_dealer: return redirect('home') - return redirect('home') dealer = get_object_or_404(models.Dealer, slug=dealer_slug) - if request.method == 'POST': if request.method == 'POST': form = forms.TicketForm(request.POST) if form.is_valid(): @@ -12085,13 +11433,10 @@ def create_ticket(request,dealer_slug): instance.save() messages.success(request, 'Your support ticket has been submitted successfully!') return redirect('ticket_list',dealer_slug=dealer.slug) - messages.success(request, 'Your support ticket has been submitted successfully!') - return redirect('ticket_list',dealer_slug=dealer.slug) else: form = forms.TicketForm() return render(request, 'support/create_ticket.html', {'form': form}) - return render(request, 'support/create_ticket.html', {'form': form}) @login_required @permission_required('inventory.view_ticket') @@ -12106,27 +11451,19 @@ def ticket_list(request,dealer_slug): @login_required @permission_required('inventory.change_ticket') -def ticket_detail(request, dealer_slug,ticket_id): -@permission_required('inventory.change_ticket') def ticket_detail(request, dealer_slug,ticket_id): dealer = get_object_or_404(models.Dealer, slug=dealer_slug) ticket = models.Ticket.objects.get(dealer=dealer,id=ticket_id) return render(request, 'support/ticket_detail.html', {'ticket': ticket}) - ticket = models.Ticket.objects.get(dealer=dealer,id=ticket_id) - return render(request, 'support/ticket_detail.html', {'ticket': ticket}) @login_required @permission_required('inventory.change_ticket') -@permission_required('inventory.change_ticket') def ticket_mark_resolved(request, ticket_id): ticket = models.Ticket.objects.get(id=ticket_id) ticket.status = 'resolved' - ticket.status = 'resolved' ticket.save() messages.success(request, 'Ticket marked as resolved successfully!') subject = 'Ticket Resolved' - messages.success(request, 'Ticket marked as resolved successfully!') - subject = 'Ticket Resolved' message = f"Your support ticket has been resolved. Please check the details below:\n\nTicket ID: {ticket.id}\nSubject: {ticket.subject}\nDescription: {ticket.description}" send_email( settings.SUPPORT_EMAIL, @@ -12135,29 +11472,18 @@ def ticket_mark_resolved(request, ticket_id): message ) return render(request, 'support/ticket_detail.html', {'ticket': ticket}) - send_email( - settings.SUPPORT_EMAIL, - ticket.dealer.user.email, - subject, - message - ) - return render(request, 'support/ticket_detail.html', {'ticket': ticket}) @login_required @permission_required('inventory.change_ticket') -@permission_required('inventory.change_ticket') def ticket_update(request, ticket_id): ticket = models.Ticket.objects.get(id=ticket_id) - if request.method == 'POST': if request.method == 'POST': form = forms.TicketResolutionForm(request.POST, instance=ticket) if form.is_valid(): form.save() messages.success(request, f'Ticket has been marked as {ticket.get_status_display()}.') return redirect('ticket_detail',dealer_slug=ticket.dealer.slug, ticket_id=ticket.id) - messages.success(request, f'Ticket has been marked as {ticket.get_status_display()}.') - return redirect('ticket_detail',dealer_slug=ticket.dealer.slug, ticket_id=ticket.id) else: form = forms.TicketResolutionForm(instance=ticket) @@ -12165,32 +11491,19 @@ def ticket_update(request, ticket_id): 'ticket': ticket, 'form': form }) - return render(request, 'support/ticket_update.html', { - 'ticket': ticket, - 'form': form - }) class ChartOfAccountModelListView(ChartOfAccountModelListViewBase): template_name = 'chart_of_accounts/coa_list.html' permission_required = 'django_ledger.view_chartofaccountmodel' - template_name = 'chart_of_accounts/coa_list.html' - permission_required = 'django_ledger.view_chartofaccountmodel' class ChartOfAccountModelCreateView(ChartOfAccountModelCreateViewBase): template_name = 'chart_of_accounts/coa_create.html' permission_required = 'django_ledger.add_chartofaccountmodel' - template_name = 'chart_of_accounts/coa_create.html' - permission_required = 'django_ledger.add_chartofaccountmodel' class ChartOfAccountModelListView(ChartOfAccountModelListViewBase): template_name = 'chart_of_accounts/coa_list.html' permission_required = 'django_ledger.view_chartofaccountmodel' - template_name = 'chart_of_accounts/coa_list.html' - permission_required = 'django_ledger.view_chartofaccountmodel' class ChartOfAccountModelUpdateView(ChartOfAccountModelUpdateViewBase): template_name = 'chart_of_accounts/coa_update.html' permission_required = 'django_ledger.change_chartofaccountmodel' - template_name = 'chart_of_accounts/coa_update.html' - permission_required = 'django_ledger.change_chartofaccountmodel' class CharOfAccountModelActionView(CharOfAccountModelActionViewBase): permission_required = 'django_ledger.change_chartofaccountmodel' - permission_required = 'django_ledger.change_chartofaccountmodel'