diff --git a/car_inventory/urls.py b/car_inventory/urls.py index 681dfa60..956e9db9 100644 --- a/car_inventory/urls.py +++ b/car_inventory/urls.py @@ -21,8 +21,8 @@ urlpatterns += i18n_patterns( path("switch_language/", views.switch_language, name="switch_language"), path("accounts/", include("allauth.urls")), # path('prometheus/', include('django_prometheus.urls')), - path("", include("inventory.urls")), path("ledger/", include("django_ledger.urls", namespace="django_ledger")), + path("", include("inventory.urls")), path("haikalbot/", include("haikalbot.urls")), path("appointment/", include("appointment.urls")), path("plans/", include("plans.urls")), diff --git a/inventory/middleware.py b/inventory/middleware.py index 033bb5c7..347fe4ec 100644 --- a/inventory/middleware.py +++ b/inventory/middleware.py @@ -126,7 +126,7 @@ class DealerSlugMiddleware: request.path_info.startswith('/en/login/') or \ request.path_info.startswith('/en/logout/') or \ request.path_info.startswith('/en/ledger/') or \ - request.path_info.startswith('/en/ledger/') or \ + request.path_info.startswith('/ar/ledger/') or \ request.path_info.startswith('/en/notifications/') or \ request.path_info.startswith('/ar/notifications/'): return None diff --git a/inventory/mixins.py b/inventory/mixins.py index e3e8fe81..474d679e 100644 --- a/inventory/mixins.py +++ b/inventory/mixins.py @@ -1,7 +1,8 @@ from django.http import Http404 -from django.shortcuts import redirect +from django.shortcuts import get_object_or_404, redirect from django.utils.translation import get_language - +from django_ledger.models import EntityModel +from inventory import models from inventory.utils import get_user_type @@ -74,3 +75,12 @@ class DealerSlugMixin: elif kwargs["dealer_slug"] != request.dealer.slug: raise Http404("Dealer slug mismatch") return super().dispatch(request, *args, **kwargs) + + +class AuthorizedEntityMixin: + def get_authorized_entity_queryset(self): + dealer = get_object_or_404(models.Dealer,slug=self.kwargs["dealer_slug"]) + return EntityModel.objects.for_user( + user_model=dealer.entity.admin, + authorized_superuser=self.get_superuser_authorization(), + ) diff --git a/inventory/models.py b/inventory/models.py index a633bf6d..a8bebb12 100644 --- a/inventory/models.py +++ b/inventory/models.py @@ -34,6 +34,7 @@ from django_ledger.models import ( EntityManagementModel, PurchaseOrderModel, ItemTransactionModel, + BillModel ) from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.models import ContentType @@ -1197,24 +1198,16 @@ class Staff(models.Model, LocalizedNameMixin): try: self.user.groups.add(group) if "accountant" in group.name.lower() or "manager" in group.name.lower(): - self.add_as_superuser() + self.add_superuser_permission() except Exception as e: print(e) - def add_as_superuser(self): - EntityManagementModel.objects.get_or_create( - user=self.user, entity=self.dealer.entity - ) + def add_superuser_permission(self): + pass + # self.dealer.entity.managers.add(self.user) def remove_superuser_permission(self): - EntityManagementModel.objects.filter( - user=self.user, entity=self.dealer.entity - ).delete() - # self.user.groups.clear() - # group = Group.objects.filter( - # customgroup__name__iexact=self.staff_type - # ).first() - # if group: - # self.add_group(group) + pass + # self.dealer.entity.managers.remove(self.user) class Meta: verbose_name = _("Staff") @@ -2552,6 +2545,10 @@ class CustomGroup(models.Model): pass def set_default_permissions(self): + est = ContentType.objects.get_for_model(EstimateModel) + bill = ContentType.objects.get_for_model(BillModel) + Permission.objects.get_or_create(name="Can approve estimate",codename="can_approve_estimate",content_type=est) + Permission.objects.get_or_create(name="Can approve bill",codename="can_approve_bill",content_type=bill) self.clear_permissions() if self.name == "Manager": self.set_permissions( @@ -2591,6 +2588,8 @@ class CustomGroup(models.Model): "chartofaccountmodel", "customermodel", "billmodel", + "can_approve_estimate" + "can_approve_bill", ], ) elif self.name == "Inventory": diff --git a/inventory/urls.py b/inventory/urls.py index 73b3902e..40b5fdee 100644 --- a/inventory/urls.py +++ b/inventory/urls.py @@ -994,12 +994,12 @@ urlpatterns = [ # CASH FLOW STATEMENTS... # Entities... path( - "entity//cash-flow-statement/", + "/entity//cash-flow-statement/", views.BaseCashFlowStatementRedirectViewBase.as_view(), name="entity-cf", ), path( - "entity//cash-flow-statement/year//", + "/entity//cash-flow-statement/year//", views.FiscalYearCashFlowStatementViewBase.as_view(), name="entity-cf-year", ), diff --git a/inventory/views.py b/inventory/views.py index cc1c20d7..a441eaea 100644 --- a/inventory/views.py +++ b/inventory/views.py @@ -19,7 +19,7 @@ from pyzbar.pyzbar import decode from urllib.parse import urlparse, urlunparse ##################################################################### -from inventory.mixins import DealerSlugMixin +from inventory.mixins import AuthorizedEntityMixin, DealerSlugMixin from inventory.models import Status as LeadStatus from django.db import IntegrityError from django.views.generic import FormView @@ -2685,7 +2685,7 @@ class GroupCreateView( group_manager, _ = models.CustomGroup.objects.get_or_create( name=instance.name, dealer=dealer, group=group ) - group_manager.set_default_permissions() + # group_manager.set_default_permissions() dealer.user.groups.add(group) return super().form_valid(form) @@ -7438,7 +7438,7 @@ class BaseBalanceSheetRedirectView(RedirectView): class FiscalYearBalanceSheetViewBase( - FiscalYearBalanceSheetView, DjangoLedgerSecurityMixIn + FiscalYearBalanceSheetView ): """ Defines a base view for the fiscal year balance sheet. @@ -7465,7 +7465,7 @@ class FiscalYearBalanceSheetViewBase( class QuarterlyBalanceSheetView( - FiscalYearBalanceSheetViewBase, QuarterlyReportMixIn, DjangoLedgerSecurityMixIn + FiscalYearBalanceSheetViewBase, QuarterlyReportMixIn ): """ Represents a quarterly balance sheet view. @@ -7488,7 +7488,7 @@ class QuarterlyBalanceSheetView( class MonthlyBalanceSheetView( - FiscalYearBalanceSheetViewBase, MonthlyReportMixIn, DjangoLedgerSecurityMixIn + FiscalYearBalanceSheetViewBase, MonthlyReportMixIn, ): """ Represents the view for the monthly balance sheet. @@ -7511,7 +7511,7 @@ class MonthlyBalanceSheetView( class DateBalanceSheetView( - FiscalYearBalanceSheetViewBase, DateReportMixIn, DjangoLedgerSecurityMixIn + FiscalYearBalanceSheetViewBase, DateReportMixIn, ): """ Represents a balance sheet view for a specific date. @@ -7541,7 +7541,7 @@ class DateBalanceSheetView( class BaseIncomeStatementRedirectViewBase( - BaseIncomeStatementRedirectView, DjangoLedgerSecurityMixIn + BaseIncomeStatementRedirectView ): """ The BaseIncomeStatementRedirectViewBase class provides functionality for handling @@ -7570,7 +7570,7 @@ class BaseIncomeStatementRedirectViewBase( class FiscalYearIncomeStatementViewBase( - FiscalYearIncomeStatementView, DjangoLedgerSecurityMixIn + FiscalYearIncomeStatementView ): """ Represents a base view for fiscal year income statement. @@ -7595,7 +7595,7 @@ class FiscalYearIncomeStatementViewBase( class QuarterlyIncomeStatementView( - FiscalYearIncomeStatementViewBase, QuarterlyReportMixIn, DjangoLedgerSecurityMixIn + FiscalYearIncomeStatementViewBase, QuarterlyReportMixIn ): """ Represents a detailed view for a quarterly income statement. @@ -7624,7 +7624,7 @@ class QuarterlyIncomeStatementView( class MonthlyIncomeStatementView( - FiscalYearIncomeStatementViewBase, MonthlyReportMixIn, DjangoLedgerSecurityMixIn + FiscalYearIncomeStatementViewBase, MonthlyReportMixIn, ): """ Represents the view for a monthly income statement in the financial @@ -7650,7 +7650,7 @@ class MonthlyIncomeStatementView( class DateModelIncomeStatementView( - FiscalYearIncomeStatementViewBase, DateReportMixIn, DjangoLedgerSecurityMixIn + FiscalYearIncomeStatementViewBase, DateReportMixIn, ): """ Represents a detailed view of an income statement for a fiscal year with additional @@ -7675,7 +7675,7 @@ class DateModelIncomeStatementView( class BaseCashFlowStatementRedirectViewBase( - BaseCashFlowStatementRedirectView, DjangoLedgerSecurityMixIn + AuthorizedEntityMixin,BaseCashFlowStatementRedirectView ): """ Base class for handling cash flow statement redirection views. @@ -7690,10 +7690,10 @@ class BaseCashFlowStatementRedirectViewBase( """ def get_redirect_url(self, *args, **kwargs): + dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"]) year = get_localdate().year - dealer = get_user_type(self.request) return reverse( - "entity-cf-year", kwargs={"entity_slug": dealer.entity.slug, "year": year} + "entity-cf-year", kwargs={"dealer_slug": dealer.slug,"entity_slug": dealer.entity.slug, "year": year} ) def get_login_url(self): @@ -7701,7 +7701,7 @@ class BaseCashFlowStatementRedirectViewBase( class FiscalYearCashFlowStatementViewBase( - FiscalYearCashFlowStatementView, DjangoLedgerSecurityMixIn + AuthorizedEntityMixin,FiscalYearCashFlowStatementView ): """ Represents a base view for fiscal year cash flow statements. @@ -7726,8 +7726,11 @@ class FiscalYearCashFlowStatementViewBase( return reverse("account_login") + + + class QuarterlyCashFlowStatementView( - FiscalYearCashFlowStatementViewBase, QuarterlyReportMixIn, DjangoLedgerSecurityMixIn + FiscalYearCashFlowStatementViewBase, QuarterlyReportMixIn, ): """ Represents a view model for quarterly cash flow statements. @@ -7755,7 +7758,7 @@ class QuarterlyCashFlowStatementView( class MonthlyCashFlowStatementView( - FiscalYearCashFlowStatementViewBase, MonthlyReportMixIn, DjangoLedgerSecurityMixIn + FiscalYearCashFlowStatementViewBase, MonthlyReportMixIn, ): """ Represents a view for monthly cash flow statements. @@ -7774,7 +7777,7 @@ class MonthlyCashFlowStatementView( class DateCashFlowStatementView( - FiscalYearCashFlowStatementViewBase, DateReportMixIn, DjangoLedgerSecurityMixIn + FiscalYearCashFlowStatementViewBase, DateReportMixIn, ): """ Representation of a detailed view for a cash flow statement associated with a specific fiscal year, @@ -7793,7 +7796,7 @@ class DateCashFlowStatementView( class EntityModelDetailHandlerViewBase( - EntityModelDetailHandlerView, DjangoLedgerSecurityMixIn + EntityModelDetailHandlerView, ): """ Handles detailed views for Entity Models along with redirection logic @@ -7835,7 +7838,7 @@ class EntityModelDetailHandlerViewBase( class EntityModelDetailBaseViewBase( - EntityModelDetailBaseView, DjangoLedgerSecurityMixIn + EntityModelDetailBaseView, ): """ Represents a base view that extends functionality for displaying detailed @@ -7892,7 +7895,7 @@ class EntityModelDetailBaseViewBase( class FiscalYearEntityModelDashboardView( - EntityModelDetailBaseViewBase, DjangoLedgerSecurityMixIn + EntityModelDetailBaseViewBase, ): """ Represents a dashboard view for fiscal year entity models. @@ -7913,7 +7916,7 @@ class FiscalYearEntityModelDashboardView( class QuarterlyEntityDashboardView( - FiscalYearEntityModelDashboardView, QuarterlyReportMixIn, DjangoLedgerSecurityMixIn + FiscalYearEntityModelDashboardView, QuarterlyReportMixIn, ): """ Represents a dashboard view for quarterly entities. @@ -7937,7 +7940,7 @@ class QuarterlyEntityDashboardView( class MonthlyEntityDashboardView( - FiscalYearEntityModelDashboardView, MonthlyReportMixIn, DjangoLedgerSecurityMixIn + FiscalYearEntityModelDashboardView, MonthlyReportMixIn, ): """ Represents a dashboard view for a specific entity's monthly report. @@ -7966,7 +7969,7 @@ class MonthlyEntityDashboardView( class DateEntityDashboardView( - FiscalYearEntityModelDashboardView, DateReportMixIn, DjangoLedgerSecurityMixIn + FiscalYearEntityModelDashboardView, DateReportMixIn, ): """ Represents a dashboard view for date-based entity data visualization. @@ -7986,7 +7989,7 @@ class DateEntityDashboardView( """ -class PayableNetAPIView(DjangoLedgerSecurityMixIn, EntityUnitMixIn, View): +class PayableNetAPIView(EntityUnitMixIn, View): """ Handles the retrieval of net payable data for authenticated users. @@ -8871,22 +8874,23 @@ def sse_stream(request): last_id = request.GET.get("last_id", 0) while True: # Check for new notifications - notifications = models.Notification.objects.filter( - user=request.user, id__gt=last_id, is_read=False - ).order_by("created") - for notification in notifications: - notification_data = { - "id": notification.id, - "message": notification.message, - "created": notification.created.isoformat(), - } + if request.user.is_authenticated: + notifications = models.Notification.objects.filter( + user=request.user, id__gt=last_id, is_read=False + ).order_by("created") + for notification in notifications: + notification_data = { + "id": notification.id, + "message": notification.message, + "created": notification.created.isoformat(), + } - yield ( - f"id: {notification.id}\n" - f"event: notification\n" - f"data: {json.dumps(notification_data)}\n\n" - ) - last_id = notification.id + yield ( + f"id: {notification.id}\n" + f"event: notification\n" + f"data: {json.dumps(notification_data)}\n\n" + ) + last_id = notification.id sleep(2) diff --git a/templates/bill/includes/card_bill.html b/templates/bill/includes/card_bill.html index 38a0a563..bf5ba80c 100644 --- a/templates/bill/includes/card_bill.html +++ b/templates/bill/includes/card_bill.html @@ -219,7 +219,7 @@ {% endif %} - {% if bill.can_approve %} + {% if bill.can_approve and perms.django_ledger.can_approve_bill %}