diff --git a/.gitignore b/.gitignore index 3643e961..4714552e 100644 --- a/.gitignore +++ b/.gitignore @@ -45,6 +45,9 @@ Makefile .idea/**/dbnavigator.xml **/migrations/** +**haikalbot/migrations/** + + # Gradle .idea/**/gradle.xml .idea/**/libraries diff --git a/.vscode/launch.json b/.vscode/launch.json index 8e4ea5ba..adc68ca8 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -8,13 +8,13 @@ "name": "Python Debugger: Django", "type": "debugpy", "request": "launch", - "args": [ + "args": [ "runserver", "0.0.0.0:8000" ], "django": true, "autoStartBrowser": false, - "program": "${workspaceFolder}/manage.py" + "program": "C:\\Users\\user\\Desktop\\haikal_projects\\venv\\bin\\activate & ${workspaceFolder}/manage.py" } ] } \ No newline at end of file diff --git a/car_inventory/urls.py b/car_inventory/urls.py index 55d3bc26..74198b9d 100644 --- a/car_inventory/urls.py +++ b/car_inventory/urls.py @@ -4,7 +4,7 @@ from django.conf.urls.static import static from django.conf import settings from django.conf.urls.i18n import i18n_patterns from inventory import views -from debug_toolbar.toolbar import debug_toolbar_urls +# from debug_toolbar.toolbar import debug_toolbar_urls # import debug_toolbar @@ -17,7 +17,7 @@ urlpatterns = [ path("api-auth/", include("rest_framework.urls")), path("api/", include("api.urls")), # path('dj-rest-auth/', include('dj_rest_auth.urls')), -] + debug_toolbar_urls() +]# + debug_toolbar_urls() urlpatterns += i18n_patterns( path("admin/", admin.site.urls), path("switch_language/", views.switch_language, name="switch_language"), diff --git a/dbtest.sqlite3 b/dbtest.sqlite3 deleted file mode 100644 index 6ec77798..00000000 Binary files a/dbtest.sqlite3 and /dev/null differ diff --git a/inventory/models.py b/inventory/models.py index 422b9490..73100891 100644 --- a/inventory/models.py +++ b/inventory/models.py @@ -2627,7 +2627,7 @@ class SaleOrder(models.Model): blank=True, ) comments = models.TextField(blank=True, null=True) - formatted_order_id = models.CharField(max_length=10, unique=True, editable=False) + formatted_order_id = models.CharField(max_length=20, unique=True, editable=False) # Status and Dates status = models.CharField( @@ -2957,7 +2957,6 @@ class CustomGroup(models.Model): "itemmodel", "invoicemodel", "vendormodel", - "journalentrymodel", "purchaseordermodel", "estimatemodel", diff --git a/inventory/views.py b/inventory/views.py index 347fd564..050b8c22 100644 --- a/inventory/views.py +++ b/inventory/views.py @@ -206,7 +206,7 @@ from .tasks import create_accounts_for_make, create_user_dealer, send_email # djago easy audit log from easyaudit.models import RequestEvent, CRUDEvent, LoginEvent from django_q.tasks import async_task -from django.db.models import Prefetch + logger = logging.getLogger(__name__) logging.basicConfig(level=logging.INFO) @@ -440,8 +440,16 @@ class ManagerDashboard(LoginRequiredMixin, TemplateView): transfer_cars = models.Car.objects.filter( dealer=dealer, status=models.CarStatusChoices.TRANSFER ).count() - reserved_percentage = reserved_cars / total_cars * 100 - sold_percentage = sold_cars / total_cars * 100 + try: + reserved_percentage = reserved_cars / total_cars * 100 + except ZeroDivisionError as e: + print(f"error: {e}") + try: + sold_percentage = sold_cars / total_cars * 100 + except ZeroDivisionError as e: + print(f"error: {e}") + + qs = ( models.Car.objects.values("id_car_make__name") .annotate(count=Count("id")) @@ -1142,7 +1150,7 @@ class CarListView(LoginRequiredMixin, PermissionRequiredMixin, ListView): def get_queryset(self): dealer = get_user_type(self.request) - qs = super().get_queryset().prefetch_related("id_car_make", "id_car_model", "id_car_trim","finances","colors") + qs = super().get_queryset() qs = qs.filter(dealer=dealer) status = self.request.GET.get("status") search = self.request.GET.get("search") @@ -1194,193 +1202,8 @@ def inventory_stats_view(request, dealer_slug): "inventory/inventory_stats.html" template. :rtype: HttpResponse """ - # cars = ( - # models.Car.objects - # .filter(dealer=request.dealer) - # .select_related( - # "id_car_make", - # "id_car_model", - # "id_car_trim__id_car_serie__id_car_model__id_car_make" - # ) - # .only( - # "id", - # "id_car_make__id_car_make", - # "id_car_make__slug", - # "id_car_make__name", - # "id_car_make__arabic_name", - # "id_car_model__id_car_model", - # "id_car_model__slug", - # "id_car_model__name", - # "id_car_model__arabic_name", - # "id_car_trim__id_car_trim", - # "id_car_trim__slug", - # "id_car_trim__name", - # "id_car_trim__id_car_serie__id_car_model__id_car_make", - # "id_car_trim__id_car_serie__id_car_model__id_car_model", - # ) - # .order_by('id_car_make', 'id_car_model', 'id_car_trim') - # ) - # # Get counts in optimized queries - # total_cars = cars.count() - # reserved_cars = models.CarReservation.objects.filter( - # car__dealer=request.dealer - # ).count() - - # # Prefetch related data if needed for additional fields - # cars = cars.prefetch_related( - # Prefetch('colors', queryset=models.CarColors.objects.select_related('exterior', 'interior')) - # ) - - # # Get distinct makes, models, trims in database-compatible way - # makes = ( - # cars.order_by('id_car_make') - # .values_list('id_car_make', flat=True) - # .distinct() - # ) - - # _models = ( - # cars.order_by('id_car_model') - # .values_list('id_car_model', flat=True) - # .distinct() - # ) - - # trims = ( - # cars.order_by('id_car_trim') - # .values_list('id_car_trim', flat=True) - # .distinct() - # ) - - # # Get counts by make/model/trim - # make_counts = dict( - # cars.values_list('id_car_make') - # .annotate(count=Count('id')) - # .order_by('id_car_make') - # ) - - # model_counts = dict( - # cars.values_list('id_car_model') - # .annotate(count=Count('id')) - # .order_by('id_car_model') - # ) - - # trim_counts = dict( - # cars.values_list('id_car_trim') - # .annotate(count=Count('id')) - # .order_by('id_car_trim') - # ) - - # # Build inventory structure - # inventory = {} - - # # Process makes - # make_objects = { - # m.id_car_make: m for m in - # models.CarMake.objects.filter(id_car_make__in=makes) - # .only('id_car_make', 'slug', 'name', 'arabic_name') - # } - - # for make_id in makes: - # if not make_id: - # continue - - # make_obj = make_objects.get(make_id) - # if not make_obj: - # continue - - # inventory[make_id] = { - # "make_id": make_id, - # "slug": make_obj.slug, - # "make_name": make_obj.get_local_name(), - # "total_cars": make_counts.get(make_id, 0), - # "models": {}, - # } - - # # Process models - # model_objects = { - # m.id_car_model: m for m in - # models.CarModel.objects.filter(id_car_model__in=_models) - # .select_related('id_car_make') - # .only('id_car_model', 'slug', 'name', 'arabic_name', 'id_car_make') - # } - - # for model_id in _models: - # if not model_id: - # continue - - # model_obj = model_objects.get(model_id) - # if not model_obj: - # continue - - # make_id = model_obj.id_car_make.id_car_make - # if make_id not in inventory: - # continue - - # inventory[make_id]["models"][model_id] = { - # "model_id": model_id, - # "slug": model_obj.slug, - # "model_name": model_obj.get_local_name(), - # "total_cars": model_counts.get(model_id, 0), - # "trims": {}, - # } - - # # Process trims - # trim_objects = { - # t.id_car_trim: t for t in - # models.CarTrim.objects.filter(id_car_trim__in=trims) - # .select_related('id_car_serie__id_car_model__id_car_make') - # .only('id_car_trim', 'slug', 'name', 'id_car_serie__id_car_model__id_car_make') - # } - - # for trim_id in trims: - # if not trim_id: - # continue - - # trim_obj = trim_objects.get(trim_id) - # if not trim_obj: - # continue - - # make_id = trim_obj.id_car_serie.id_car_model.id_car_make.id_car_make - # model_id = trim_obj.id_car_serie.id_car_model.id_car_model - - # if make_id not in inventory or model_id not in inventory[make_id]["models"]: - # continue - - # inventory[make_id]["models"][model_id]["trims"][trim_id] = { - # "trim_id": trim_id, - # "slug": trim_obj.slug, - # "trim_name": trim_obj.name, - # "total_cars": trim_counts.get(trim_id, 0), - # } - - # # Convert to final structure - # result = { - # "total_cars": total_cars, - # "reserved_cars": reserved_cars, - # "makes": [ - # { - # "make_id": make_data["make_id"], - # "slug": make_data["slug"], - # "make_name": make_data["make_name"], - # "total_cars": make_data["total_cars"], - # "models": [ - # { - # "model_id": model_data["model_id"], - # "slug": model_data["slug"], - # "model_name": model_data["model_name"], - # "total_cars": model_data["total_cars"], - # "trims": list(model_data["trims"].values()), - # } - # for model_data in make_data["models"].values() - # if model_data["model_id"] # Skip empty models - # ], - # } - # for make_data in inventory.values() - # if make_data["make_id"] # Skip empty makes - # ], - # } - ############################################### - # # Base queryset for cars belonging to the dealer + # Base queryset for cars belonging to the dealer cars = models.Car.objects.filter(dealer=request.dealer) # Count for total, reserved, showroom, and unreserved cars @@ -1620,18 +1443,6 @@ class CarDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView): context_object_name = "car" permission_required = ["inventory.view_car"] - def get_queryset(self): - qs = super().get_queryset() - qs = qs.select_related( - "id_car_make", - "id_car_model", - "id_car_trim", - "colors", - "finances", - "vendor", - "registrations" - ) - return qs class CarFinanceCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView): """ @@ -2716,6 +2527,8 @@ def vendorDetailView(request, dealer_slug,slug): return render( request, template_name="vendors/view_vendor.html", context={"vendor": vendor} ) + + class VendorCreateView( @@ -4062,7 +3875,7 @@ class BankAccountDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailV template_name = "ledger/bank_accounts/bank_account_detail.html" context_object_name = "bank_account" permission_required = ["django_ledger.view_bankaccountmodel"] - + def get_queryset(self): dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"]) query=self.request.GET.get('q') @@ -5570,6 +5383,7 @@ def PaymentCreateView(request, dealer_slug, pk): model = invoice if invoice else bill entity = dealer.entity form = forms.PaymentForm() + breakpoint() if request.method == "POST": form = forms.PaymentForm(request.POST) @@ -5826,8 +5640,7 @@ class LeadListView(LoginRequiredMixin, PermissionRequiredMixin, ListView): def get_queryset(self): dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"]) query = self.request.GET.get("q") - qs = models.Lead.objects.select_related("staff","id_car_make","id_car_model","customer").filter(dealer=dealer).exclude(status="converted") - + qs = models.Lead.objects.filter(dealer=dealer).exclude(status="converted") if query: qs = qs.filter(Q(first_name__icontains=query) | Q(last_name__icontains=query) @@ -5843,7 +5656,8 @@ class LeadListView(LoginRequiredMixin, PermissionRequiredMixin, ListView): if self.request.is_staff: return qs.filter(staff=self.request.staff) return models.Lead.objects.none() - + + class LeadDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView): """ @@ -6909,9 +6723,9 @@ class OpportunityListView(LoginRequiredMixin,PermissionRequiredMixin, ListView): Q(customer__first_name__icontains=search) | Q(customer__last_name__icontains=search) | Q(customer__email__icontains=search) - + ) - + # Stage filter stage = self.request.GET.get("stage") @@ -7330,7 +7144,7 @@ class ItemExpenseListView(LoginRequiredMixin, PermissionRequiredMixin, ListView) # def get_queryset(self): # dealer = get_user_type(self.request) # return dealer.entity.get_items_expenses() - + def get_queryset(self): dealer = get_user_type(self.request) query=self.request.GET.get('q') @@ -8911,7 +8725,7 @@ class LedgerModelListView(LoginRequiredMixin,PermissionRequiredMixin, ListView, show_visible = False allow_empty = True paginate_by = 30 - permission_required = "django_ledger.view_ledgermodel" + def get_queryset(self): qs = super().get_queryset() @@ -9228,7 +9042,7 @@ class JournalEntryModelTXSDetailView(JournalEntryModelTXSDetailViewBase): """ template_name = "ledger/journal_entry/journal_entry_txs.html" - + @login_required @permission_required("django_ledger.change_ledgermodel", raise_exception=True) @@ -10204,9 +10018,9 @@ class PurchaseOrderListView(LoginRequiredMixin, PermissionRequiredMixin, ListVie if query: qs=apply_search_filters(qs,query) return qs - - - + + + # def get_queryset(self): # dealer = get_user_type(self.request) # entity = dealer.entity @@ -10340,28 +10154,11 @@ class BillModelActionMarkAsInReviewView(BaseBillActionView): class BillModelActionMarkAsApprovedView(BaseBillActionView): action_name = "mark_as_approved" - def get_redirect_url(self, dealer_slug, entity_slug, bill_pk, *args, **kwargs): - if self.request.is_manager: - messages.add_message( - self.request, - message="Bill updated successfully.", - level=messages.SUCCESS, - ) - return reverse("home",kwargs={"dealer_slug": dealer_slug}) - - return reverse( - "bill-update", - kwargs={ - "dealer_slug": dealer_slug, - "entity_slug": entity_slug, - "bill_pk": bill_pk, - }, - ) - class BillModelActionMarkAsPaidView(BaseBillActionView): action_name = "mark_as_paid" + class BillModelActionDeleteView(BaseBillActionView): action_name = "mark_as_delete" diff --git a/templates/bill/bill_create.html b/templates/bill/bill_create.html index 0aeabe45..4e0a8ae7 100644 --- a/templates/bill/bill_create.html +++ b/templates/bill/bill_create.html @@ -5,7 +5,7 @@ {% load crispy_forms_filters %} {% block content %} -
{{ bill.vendor.address_1 }}
- + {% if not bill.is_past_due %}{% trans 'Due in' %}: {{ bill.date_due | timeuntil }} @@ -91,12 +93,20 @@