diff --git a/horilla/horilla_apps.py b/horilla/horilla_apps.py index 4699d54c6..a8e565a21 100644 --- a/horilla/horilla_apps.py +++ b/horilla/horilla_apps.py @@ -20,6 +20,7 @@ INSTALLED_APPS.append("biometric") INSTALLED_APPS.append("helpdesk") INSTALLED_APPS.append("offboarding") INSTALLED_APPS.append("horilla_backup") +INSTALLED_APPS.append("project") if settings.env("AWS_ACCESS_KEY_ID", default=None) and "storages" not in INSTALLED_APPS: INSTALLED_APPS.append("storages") @@ -55,6 +56,7 @@ SIDEBARS = [ "offboarding", "asset", "helpdesk", + "project", ] WHITE_LABELLING = False diff --git a/project/admin.py b/project/admin.py index 3211d17b0..442b817f7 100644 --- a/project/admin.py +++ b/project/admin.py @@ -1,9 +1,9 @@ -from django.contrib import admin - -from .models import * - -# Register your models here. -admin.site.register(Project) -admin.site.register(ProjectStage) -admin.site.register(Task) -admin.site.register(TimeSheet) +from django.contrib import admin + +from .models import * + +# Register your models here. +admin.site.register(Project) +admin.site.register(ProjectStage) +admin.site.register(Task) +admin.site.register(TimeSheet) diff --git a/project/apps.py b/project/apps.py index 1a57dcddd..37068f2d2 100644 --- a/project/apps.py +++ b/project/apps.py @@ -1,28 +1,28 @@ -from django.apps import AppConfig - - -class ProjectConfig(AppConfig): - default_auto_field = "django.db.models.BigAutoField" - name = "project" - - def ready(self): - from django.urls import include, path - - from horilla.urls import urlpatterns - - urlpatterns.append( - path("project/", include("project.urls")), - ) - super().ready() - try: - from django.urls import include, path - - from horilla.urls import urlpatterns - - urlpatterns.append( - path("project/", include("project.urls")), - ) - except: - """ - Models not ready yet - """ +from django.apps import AppConfig + + +class ProjectConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "project" + + def ready(self): + from django.urls import include, path + + from horilla.urls import urlpatterns + + urlpatterns.append( + path("project/", include("project.urls")), + ) + super().ready() + try: + from django.urls import include, path + + from horilla.urls import urlpatterns + + urlpatterns.append( + path("project/", include("project.urls")), + ) + except: + """ + Models not ready yet + """ diff --git a/project/cbv/accessibility.py b/project/cbv/accessibility.py index a2375fed9..307dcbd34 100644 --- a/project/cbv/accessibility.py +++ b/project/cbv/accessibility.py @@ -1,39 +1,39 @@ -""" -Accessibility -""" - -from django.contrib.auth.context_processors import PermWrapper - -from employee.models import Employee -from project.models import Project, Task - - -def task_crud_accessibility( - request, instance: object = None, user_perms: PermWrapper = [], *args, **kwargs -) -> bool: - """ - to access crud operations - """ - employee = request.user.employee_get - is_task_manager = employee in instance.task_managers.all() - is_project_manager = employee in instance.project.managers.all() - if ( - request.user.has_perm("project.view_task") - or is_project_manager - or is_task_manager - ): - return True - else: - return False - - -def project_manager_accessibility( - request, instance: object = None, user_perms: PermWrapper = [], *args, **kwargs -) -> bool: - """ - to access edit Project - """ - return ( - request.user.employee_get in instance.managers.all() - or request.user.is_superuser - ) +""" +Accessibility +""" + +from django.contrib.auth.context_processors import PermWrapper + +from employee.models import Employee +from project.models import Project, Task + + +def task_crud_accessibility( + request, instance: object = None, user_perms: PermWrapper = [], *args, **kwargs +) -> bool: + """ + to access crud operations + """ + employee = request.user.employee_get + is_task_manager = employee in instance.task_managers.all() + is_project_manager = employee in instance.project.managers.all() + if ( + request.user.has_perm("project.view_task") + or is_project_manager + or is_task_manager + ): + return True + else: + return False + + +def project_manager_accessibility( + request, instance: object = None, user_perms: PermWrapper = [], *args, **kwargs +) -> bool: + """ + to access edit Project + """ + return ( + request.user.employee_get in instance.managers.all() + or request.user.is_superuser + ) diff --git a/project/cbv/cbv_decorators.py b/project/cbv/cbv_decorators.py index fce0ffc69..e104ac830 100644 --- a/project/cbv/cbv_decorators.py +++ b/project/cbv/cbv_decorators.py @@ -1,44 +1,44 @@ -from django.contrib import messages -from django.http import HttpResponseRedirect - -from horilla.horilla_middlewares import _thread_locals -from project.methods import ( - any_project_manager, - any_project_member, - any_task_manager, - any_task_member, - has_subordinates, -) - -# from project.sidebar import has_subordinates - - -decorator_with_arguments = ( - lambda decorator: lambda *args, **kwargs: lambda func: decorator( - func, *args, **kwargs - ) -) - - -@decorator_with_arguments -def is_projectmanager_or_member_or_perms(function, perm): - def _function(self, *args, **kwargs): - """ - This method is used to check the employee is project manager or not - """ - request = getattr(_thread_locals, "request") - if not getattr(self, "request", None): - self.request = request - user = request.user - if ( - user.has_perm(perm) - or any_project_manager(user) - or any_project_member(user) - or any_task_manager(user) - or any_task_member(user) - ): - return function(self, *args, **kwargs) - messages.info(request, "You don't have permission.") - return HttpResponseRedirect(request.META.get("HTTP_REFERER", "/")) - - return _function +from django.contrib import messages +from django.http import HttpResponseRedirect + +from horilla.horilla_middlewares import _thread_locals +from project.methods import ( + any_project_manager, + any_project_member, + any_task_manager, + any_task_member, + has_subordinates, +) + +# from project.sidebar import has_subordinates + + +decorator_with_arguments = ( + lambda decorator: lambda *args, **kwargs: lambda func: decorator( + func, *args, **kwargs + ) +) + + +@decorator_with_arguments +def is_projectmanager_or_member_or_perms(function, perm): + def _function(self, *args, **kwargs): + """ + This method is used to check the employee is project manager or not + """ + request = getattr(_thread_locals, "request") + if not getattr(self, "request", None): + self.request = request + user = request.user + if ( + user.has_perm(perm) + or any_project_manager(user) + or any_project_member(user) + or any_task_manager(user) + or any_task_member(user) + ): + return function(self, *args, **kwargs) + messages.info(request, "You don't have permission.") + return HttpResponseRedirect(request.META.get("HTTP_REFERER", "/")) + + return _function diff --git a/project/cbv/dashboard.py b/project/cbv/dashboard.py index 781d8c9a1..5c8deee8d 100644 --- a/project/cbv/dashboard.py +++ b/project/cbv/dashboard.py @@ -1,108 +1,108 @@ -""" -Dashbord of project -""" - -import calendar -import datetime -from typing import Any - -from django.db.models import Count, Q -from django.db.models.query import QuerySet -from django.urls import resolve, reverse -from django.utils.decorators import method_decorator -from django.utils.translation import gettext_lazy as _ - -from base.methods import get_subordinates -from horilla_views.cbv_methods import login_required -from horilla_views.generic.cbv.views import HorillaDetailedView, HorillaListView -from project.cbv.cbv_decorators import is_projectmanager_or_member_or_perms -from project.filters import ProjectFilter -from project.models import Project - - -@method_decorator(login_required, name="dispatch") -@method_decorator( - is_projectmanager_or_member_or_perms("project.view_project"), name="dispatch" -) -class ProjectsDueInMonth(HorillaListView): - - model = Project - filter_class = ProjectFilter - bulk_select_option = False - columns = [(_("Project"), "title", "get_avatar")] - show_filter_tags = False - - def get_queryset(self): - queryset = super().get_queryset() - if not self.request.user.has_perm("project.view_project"): - employee = self.request.user.employee_get - task_filter = queryset.filter( - Q(task__task_members=employee) | Q(task__task_manager=employee) - ) - project_filter = queryset.filter(Q(manager=employee) | Q(members=employee)) - queryset = task_filter | project_filter - today = datetime.date.today() - first_day = today.replace(day=1) - last_day = calendar.monthrange(today.year, today.month)[1] - last_day_of_month = today.replace(day=last_day) - queryset = queryset.filter( - Q(end_date__gte=first_day) & Q(end_date__lte=last_day_of_month) - ).exclude(status="expired") - return queryset - - def __init__(self, **kwargs: Any) -> None: - super().__init__(**kwargs) - self.search_url = reverse("projects-due-in-this-month") - - row_attrs = """ - hx-get='{get_detail_url}?instance_ids={ordered_ids}' - hx-target="#genericModalBody" - data-target="#genericModal" - data-toggle="oh-modal-toggle" - """ - - -class ProjectDetailView(HorillaDetailedView): - """ - detail view of the projects - """ - - model = Project - title = _("Details") - header = {"title": "title", "subtitle": "", "avatar": "get_avatar"} - body = [ - (_("Manager"), "manager"), - (_("Members"), "get_members"), - (_("Status"), "status_column"), - (_("No of Tasks"), "task_count"), - (_("Start date"), "start_date"), - (_("End date"), "end_date"), - (_("Document"), "get_document_html"), - (_("Description"), "description"), - ] - - def __init__(self, **kwargs: Any) -> None: - super().__init__(**kwargs) - instnce_id = resolve(self.request.path_info).kwargs.get("pk") - employee = self.request.user.employee_get - project = Project.objects.get(id=instnce_id) - if ( - employee in project.managers.all() - or employee in project.members.all() - or self.request.user.has_perm("project.view_project") - ): - self.actions = [ - { - "action": _("View Project"), - "icon": "create-outline", - "attrs": """ - class = "oh-btn oh-btn--info w-100" - {redirect} - """, - } - ] - - def get_queryset(self) -> QuerySet[Any]: - queryset = super().get_queryset() - queryset = queryset.annotate(task_count=Count("task")) - return queryset +""" +Dashbord of project +""" + +import calendar +import datetime +from typing import Any + +from django.db.models import Count, Q +from django.db.models.query import QuerySet +from django.urls import resolve, reverse +from django.utils.decorators import method_decorator +from django.utils.translation import gettext_lazy as _ + +from base.methods import get_subordinates +from horilla_views.cbv_methods import login_required +from horilla_views.generic.cbv.views import HorillaDetailedView, HorillaListView +from project.cbv.cbv_decorators import is_projectmanager_or_member_or_perms +from project.filters import ProjectFilter +from project.models import Project + + +@method_decorator(login_required, name="dispatch") +@method_decorator( + is_projectmanager_or_member_or_perms("project.view_project"), name="dispatch" +) +class ProjectsDueInMonth(HorillaListView): + + model = Project + filter_class = ProjectFilter + bulk_select_option = False + columns = [(_("Project"), "title", "get_avatar")] + show_filter_tags = False + + def get_queryset(self): + queryset = super().get_queryset() + if not self.request.user.has_perm("project.view_project"): + employee = self.request.user.employee_get + task_filter = queryset.filter( + Q(task__task_members=employee) | Q(task__task_manager=employee) + ) + project_filter = queryset.filter(Q(manager=employee) | Q(members=employee)) + queryset = task_filter | project_filter + today = datetime.date.today() + first_day = today.replace(day=1) + last_day = calendar.monthrange(today.year, today.month)[1] + last_day_of_month = today.replace(day=last_day) + queryset = queryset.filter( + Q(end_date__gte=first_day) & Q(end_date__lte=last_day_of_month) + ).exclude(status="expired") + return queryset + + def __init__(self, **kwargs: Any) -> None: + super().__init__(**kwargs) + self.search_url = reverse("projects-due-in-this-month") + + row_attrs = """ + hx-get='{get_detail_url}?instance_ids={ordered_ids}' + hx-target="#genericModalBody" + data-target="#genericModal" + data-toggle="oh-modal-toggle" + """ + + +class ProjectDetailView(HorillaDetailedView): + """ + detail view of the projects + """ + + model = Project + title = _("Details") + header = {"title": "title", "subtitle": "", "avatar": "get_avatar"} + body = [ + (_("Manager"), "manager"), + (_("Members"), "get_members"), + (_("Status"), "status_column"), + (_("No of Tasks"), "task_count"), + (_("Start date"), "start_date"), + (_("End date"), "end_date"), + (_("Document"), "get_document_html"), + (_("Description"), "description"), + ] + + def __init__(self, **kwargs: Any) -> None: + super().__init__(**kwargs) + instnce_id = resolve(self.request.path_info).kwargs.get("pk") + employee = self.request.user.employee_get + project = Project.objects.get(id=instnce_id) + if ( + employee in project.managers.all() + or employee in project.members.all() + or self.request.user.has_perm("project.view_project") + ): + self.actions = [ + { + "action": _("View Project"), + "icon": "create-outline", + "attrs": """ + class = "oh-btn oh-btn--info w-100" + {redirect} + """, + } + ] + + def get_queryset(self) -> QuerySet[Any]: + queryset = super().get_queryset() + queryset = queryset.annotate(task_count=Count("task")) + return queryset diff --git a/project/cbv/project_stage.py b/project/cbv/project_stage.py index 9d909d630..91c72ac95 100644 --- a/project/cbv/project_stage.py +++ b/project/cbv/project_stage.py @@ -1,137 +1,137 @@ -""" -This page handles the cbv methods for project stages -""" - -import logging -from typing import Any - -from django.contrib import messages -from django.http import HttpResponse -from django.utils.decorators import method_decorator -from django.utils.translation import gettext_lazy as _ - -from horilla_views.cbv_methods import login_required -from horilla_views.generic.cbv.views import HorillaFormView - -# from project.decorator import project_delete_permission -from project.forms import ProjectStageForm -from project.methods import you_dont_have_permission -from project.models import Project, ProjectStage - -logger = logging.getLogger(__name__) - - -@method_decorator(login_required, name="dispatch") -# @method_decorator(project_delete_permission, name="dispatch") -class ProjectStageCreateForm(HorillaFormView): - """ - form view fro create and edit stages - """ - - form_class = ProjectStageForm - model = ProjectStage - new_display_title = _("Create Project Stage") - - def get(self, request, *args, pk=None, **kwargs): - if request.GET.get("project_id"): - project_id = request.GET.get("project_id") - else: - project_id = self.kwargs.get("project_id") - stage_id = self.kwargs.get("pk") - if project_id: - try: - if project_id: - project = Project.objects.filter(id=project_id).first() - elif stage_id: - project = ProjectStage.objects.filter(id=stage_id).first().project - if ( - request.user.employee_get in project.managers.all() - or request.user.is_superuser - ): - return super().get(request, *args, pk=pk, **kwargs) - else: - return you_dont_have_permission(request) - except Exception as e: - logger.error(e) - messages.error(request, _("Something went wrong!")) - return HttpResponse("") - else: - return super().get(request, *args, pk=pk, **kwargs) - - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - project_id = self.kwargs.get("project_id") - if project_id: - project = Project.objects.get(id=project_id) - self.form.fields["project"].initial = project - if self.form.instance.pk: - self.form_class.verbose_name = _("Update Project Stage") - return context - - def form_valid(self, form: ProjectStageForm) -> HttpResponse: - if form.is_valid(): - if form.instance.pk: - project_id = self.form.cleaned_data["project"].id - message = _(f"{self.form.instance} Updated") - else: - project_id = self.kwargs.get("project_id") - message = _("New project stage created") - form.save() - messages.success(self.request, message) - return self.HttpResponse( - f"" - ) - return super().form_valid(form) - - -from django import forms - - -class StageDynamicCreateForm(ProjectStageCreateForm): - """ - dynamic create form for stage - """ - - is_dynamic_create_view = True - template_name = HorillaFormView.template_name - - def get_initial(self): - initial = super().get_initial() - project = self.request.GET.get("project") - initial["project"] = project - return initial - - def init_form(self, *args, data, files, instance=None, **kwargs): - initial = self.get_initial() - form = super().init_form( - *args, data=data, files=files, instance=instance, initial=initial, **kwargs - ) - if not initial.get("project"): - form.fields["project"].widget = forms.Select( - attrs={"class": "oh-select oh-select-2 w-100 oh-select2"} - ) - form.fields["project"].queryset = Project.objects.all() - - return form - - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - project_id = self.request.GET.get("project_id") - if not project_id: - project_id = self.request.GET.get("project") - if project_id: - project = Project.objects.get(id=project_id) - self.form.fields["project"].initial = project - self.form.fields["project"].choices = [(project.id, project.title)] - return context - - def form_valid(self, form: ProjectStageForm) -> HttpResponse: - if form.is_valid(): - if form.instance.pk: - message = _(f"{self.form.instance} Updated") - else: - message = _("New project stage created") - form.save() - messages.success(self.request, _(message)) - return self.HttpResponse() - return super().form_valid(form) +""" +This page handles the cbv methods for project stages +""" + +import logging +from typing import Any + +from django.contrib import messages +from django.http import HttpResponse +from django.utils.decorators import method_decorator +from django.utils.translation import gettext_lazy as _ + +from horilla_views.cbv_methods import login_required +from horilla_views.generic.cbv.views import HorillaFormView + +# from project.decorator import project_delete_permission +from project.forms import ProjectStageForm +from project.methods import you_dont_have_permission +from project.models import Project, ProjectStage + +logger = logging.getLogger(__name__) + + +@method_decorator(login_required, name="dispatch") +# @method_decorator(project_delete_permission, name="dispatch") +class ProjectStageCreateForm(HorillaFormView): + """ + form view fro create and edit stages + """ + + form_class = ProjectStageForm + model = ProjectStage + new_display_title = _("Create Project Stage") + + def get(self, request, *args, pk=None, **kwargs): + if request.GET.get("project_id"): + project_id = request.GET.get("project_id") + else: + project_id = self.kwargs.get("project_id") + stage_id = self.kwargs.get("pk") + if project_id: + try: + if project_id: + project = Project.objects.filter(id=project_id).first() + elif stage_id: + project = ProjectStage.objects.filter(id=stage_id).first().project + if ( + request.user.employee_get in project.managers.all() + or request.user.is_superuser + ): + return super().get(request, *args, pk=pk, **kwargs) + else: + return you_dont_have_permission(request) + except Exception as e: + logger.error(e) + messages.error(request, _("Something went wrong!")) + return HttpResponse("") + else: + return super().get(request, *args, pk=pk, **kwargs) + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + project_id = self.kwargs.get("project_id") + if project_id: + project = Project.objects.get(id=project_id) + self.form.fields["project"].initial = project + if self.form.instance.pk: + self.form_class.verbose_name = _("Update Project Stage") + return context + + def form_valid(self, form: ProjectStageForm) -> HttpResponse: + if form.is_valid(): + if form.instance.pk: + project_id = self.form.cleaned_data["project"].id + message = _(f"{self.form.instance} Updated") + else: + project_id = self.kwargs.get("project_id") + message = _("New project stage created") + form.save() + messages.success(self.request, message) + return self.HttpResponse( + f"" + ) + return super().form_valid(form) + + +from django import forms + + +class StageDynamicCreateForm(ProjectStageCreateForm): + """ + dynamic create form for stage + """ + + is_dynamic_create_view = True + template_name = HorillaFormView.template_name + + def get_initial(self): + initial = super().get_initial() + project = self.request.GET.get("project") + initial["project"] = project + return initial + + def init_form(self, *args, data, files, instance=None, **kwargs): + initial = self.get_initial() + form = super().init_form( + *args, data=data, files=files, instance=instance, initial=initial, **kwargs + ) + if not initial.get("project"): + form.fields["project"].widget = forms.Select( + attrs={"class": "oh-select oh-select-2 w-100 oh-select2"} + ) + form.fields["project"].queryset = Project.objects.all() + + return form + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + project_id = self.request.GET.get("project_id") + if not project_id: + project_id = self.request.GET.get("project") + if project_id: + project = Project.objects.get(id=project_id) + self.form.fields["project"].initial = project + self.form.fields["project"].choices = [(project.id, project.title)] + return context + + def form_valid(self, form: ProjectStageForm) -> HttpResponse: + if form.is_valid(): + if form.instance.pk: + message = _(f"{self.form.instance} Updated") + else: + message = _("New project stage created") + form.save() + messages.success(self.request, _(message)) + return self.HttpResponse() + return super().form_valid(form) diff --git a/project/cbv/projects.py b/project/cbv/projects.py index 2ddac6f0a..85f25e9d9 100644 --- a/project/cbv/projects.py +++ b/project/cbv/projects.py @@ -1,521 +1,521 @@ -""" -CBV of projects page -""" - -from typing import Any - -from django.contrib import messages -from django.db.models import Q -from django.http import HttpResponse -from django.urls import reverse -from django.utils.decorators import method_decorator -from django.utils.translation import gettext_lazy as _ -from django.views.generic import ListView - -from employee.models import Employee -from horilla.horilla_middlewares import _thread_locals -from horilla_views.cbv_methods import login_required, permission_required -from horilla_views.generic.cbv.views import ( - HorillaCardView, - HorillaFormView, - HorillaListView, - HorillaNavView, - TemplateView, -) -from project.cbv.cbv_decorators import is_projectmanager_or_member_or_perms -from project.filters import ProjectFilter -from project.forms import ProjectForm -from project.methods import ( - any_project_manager, - any_project_member, - is_project_manager_or_super_user, - you_dont_have_permission, -) -from project.models import Project - - -@method_decorator(login_required, name="dispatch") -@method_decorator( - is_projectmanager_or_member_or_perms("project.view_project"), name="dispatch" -) -class ProjectsView(TemplateView): - """ - for projects page - """ - - template_name = "cbv/projects/projects.html" - - -@method_decorator(login_required, name="dispatch") -@method_decorator( - is_projectmanager_or_member_or_perms("project.view_project"), name="dispatch" -) -class ProjectsNavView(HorillaNavView): - """ - Nav bar - """ - - template_name = "cbv/projects/project_nav.html" - - def __init__(self, **kwargs: Any) -> None: - super().__init__(**kwargs) - self.search_url = reverse("project-list-view") - # self.search_in = [ - # ("status", _("Managers")), - # ("members", _("Members")), - # ] - if self.request.user.has_perm("project.view_project"): - self.actions = [ - { - "action": _("Import"), - "attrs": """ - id="importProject" - data-toggle="oh-modal-toggle" - data-target="#projectImport" - style="cursor: pointer;" - """, - }, - { - "action": _("Export"), - "attrs": """ - id="exportProject" - style="cursor: pointer;" - """, - }, - { - "action": _("Archive"), - "attrs": """ - id="archiveProject" - style="cursor: pointer;" - """, - }, - { - "action": _("Un-archive"), - "attrs": """ - id="unArchiveProject" - style="cursor: pointer;" - """, - }, - { - "action": _("Delete"), - "attrs": """ - class="oh-dropdown__link--danger" - data-action ="delete" - id="deleteProject" - style="cursor: pointer; color:red !important" - """, - }, - ] - self.view_types = [ - { - "type": "list", - "icon": "list-outline", - "url": reverse("project-list-view"), - "attrs": """ - title ='List' - """, - }, - { - "type": "card", - "icon": "grid-outline", - "url": reverse("project-card-view"), - "attrs": """ - title ='Card' - """, - }, - ] - if self.request.user.has_perm("project.add_project"): - self.create_attrs = f""" - onclick = "event.stopPropagation();" - data-toggle="oh-modal-toggle" - data-target="#genericModal" - hx-target="#genericModalBody" - hx-get="{reverse('create-project')}" - """ - - group_by_fields = [ - ("status", _("Status")), - ("is_active", _("Is active")), - ] - nav_title = _("Projects") - filter_instance = ProjectFilter() - filter_form_context_name = "form" - filter_body_template = "cbv/projects/filter.html" - search_swap_target = "#listContainer" - - -@method_decorator(login_required, name="dispatch") -@method_decorator( - is_projectmanager_or_member_or_perms("project.view_project"), name="dispatch" -) -class ProjectsList(HorillaListView): - """ - Projects list view - """ - - def get_queryset(self): - queryset = super().get_queryset() - if not self.request.user.has_perm("project.view_project"): - employee = self.request.user.employee_get - task_filter = queryset.filter( - Q(task__task_members=employee) | Q(task__task_managers=employee) - ) - project_filter = queryset.filter(Q(managers=employee) | Q(members=employee)) - queryset = task_filter | project_filter - return queryset.distinct() - - def __init__(self, **kwargs: Any) -> None: - super().__init__(**kwargs) - self.search_url = reverse("project-list-view") - if self.request.user.is_superuser: - self.action_method = "actions" - - model = Project - filter_class = ProjectFilter - - columns = [ - (_("Project"), "title"), - (_("Project Managers"), "get_managers"), - (_("Project Members"), "get_members"), - (_("Status"), "status_column"), - (_("Start Date"), "start_date"), - (_("End Date"), "end_date"), - (_("File"), "get_document_html"), - (_("Description"), "get_description"), - ] - - sortby_mapping = [ - ("Project", "title"), - ("Start Date", "start_date"), - ("End Date", "end_date"), - ] - - row_status_indications = [ - ( - "new--dot", - _("New"), - """ - onclick=" - $('#applyFilter').closest('form').find('[name=status]').val('new'); - $('#applyFilter').click(); - " - """, - ), - ( - "in-progress--dot", - _("In progress"), - """ - onclick=" - $('#applyFilter').closest('form').find('[name=status]').val('in_progress'); - $('#applyFilter').click(); - - " - """, - ), - ( - "completed--dot", - _("Completed"), - """ - onclick=" - $('#applyFilter').closest('form').find('[name=status]').val('completed'); - $('#applyFilter').click(); - - " - """, - ), - ( - "on-hold--dot", - _("On Hold"), - """ - onclick=" - $('#applyFilter').closest('form').find('[name=status]').val('on_hold'); - $('#applyFilter').click(); - - " - """, - ), - ( - "cancelled--dot", - _("Completed"), - """ - onclick=" - $('#applyFilter').closest('form').find('[name=status]').val('cancelled'); - $('#applyFilter').click(); - - " - """, - ), - ( - "expired--dot", - _("Expired"), - """ - onclick=" - $('#applyFilter').closest('form').find('[name=status]').val('expired'); - $('#applyFilter').click(); - - " - """, - ), - ] - - row_status_class = "status-{status}" - - row_attrs = """ - {redirect} - """ - - -@method_decorator(login_required, name="dispatch") -# @method_decorator(permission_required("project.add_project"), name="dispatch") -class ProjectFormView(HorillaFormView): - """ - form view for create project - """ - - form_class = ProjectForm - model = Project - new_display_title = _("Create Project") - - def __init__(self, **kwargs): - super().__init__(**kwargs) - user = self.request.user - - if not user.is_superuser and not user.has_perm("project.add_project"): - self.template_name = "decorator_404.html" - - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - if self.form.instance.pk: - self.form_class.verbose_name = _("Update project") - return context - - def form_valid(self, form: ProjectForm) -> HttpResponse: - if form.is_valid(): - if form.instance.pk: - message = _(f"{self.form.instance} Updated") - HTTP_REFERER = self.request.META.get("HTTP_REFERER", None) - if HTTP_REFERER and "task-view/" in HTTP_REFERER: - form.save() - messages.success(self.request, message) - return self.HttpResponse( - "" - ) - else: - message = _("New project created") - form.save() - messages.success(self.request, _(message)) - return self.HttpResponse() - return super().form_valid(form) - - -class DynamicProjectCreationFormView(ProjectFormView): - - is_dynamic_create_view = True - - -@method_decorator(login_required, name="dispatch") -@method_decorator( - is_projectmanager_or_member_or_perms("project.view_project"), name="dispatch" -) -class ProjectCardView(HorillaCardView): - """ - For card view - """ - - model = Project - filter_class = ProjectFilter - - def get_queryset(self): - queryset = super().get_queryset() - if not self.request.user.has_perm("project.view_project"): - employee = self.request.user.employee_get - task_filter = queryset.filter( - Q(task__task_members=employee) | Q(task__task_managers=employee) - ) - project_filter = queryset.filter(Q(managers=employee) | Q(members=employee)) - queryset = task_filter | project_filter - return queryset.distinct() - - def __init__(self, **kwargs: Any) -> None: - super().__init__(**kwargs) - self.search_url = reverse("project-card-view") - if ( - self.request.user.has_perm("project.change_project") - or self.request.user.has_perm("project.delete_project") - or any_project_manager(self.request.user) - or any_project_member(self.request.user) - ): - self.actions = [ - { - "action": "Edit", - "accessibility": "project.cbv.accessibility.project_manager_accessibility", - "attrs": """ - hx-get='{get_update_url}' - hx-target='#genericModalBody' - data-toggle="oh-modal-toggle" - data-target="#genericModal" - class="oh-dropdown__link" - """, - }, - { - "action": "archive_status", - "accessibility": "project.cbv.accessibility.project_manager_accessibility", - "attrs": """ - href="{get_archive_url}" - onclick="return confirm('Do you want to {archive_status} this project?')" - class="oh-dropdown__link" - """, - }, - { - "action": "Delete", - "accessibility": "project.cbv.accessibility.project_manager_accessibility", - "attrs": """ - onclick=" - event.stopPropagation() - deleteItem({get_delete_url}); - " - class="oh-dropdown__link oh-dropdown__link--danger" - """, - }, - ] - - details = { - "image_src": "get_avatar", - "title": "{get_task_badge_html}", - "subtitle": "Status : {status_column}
Start date : {start_date}
End date : {end_date}", - } - card_status_class = "status-{status}" - - card_status_indications = [ - ( - "new--dot", - _("New"), - """ - onclick=" - $('#applyFilter').closest('form').find('[name=status]').val('new'); - $('#applyFilter').click(); - " - """, - ), - ( - "in-progress--dot", - _("In progress"), - """ - onclick=" - $('#applyFilter').closest('form').find('[name=status]').val('in_progress'); - $('#applyFilter').click(); - - " - """, - ), - ( - "completed--dot", - _("Completed"), - """ - onclick=" - $('#applyFilter').closest('form').find('[name=status]').val('completed'); - $('#applyFilter').click(); - - " - """, - ), - ( - "on-hold--dot", - _("On Hold"), - """ - onclick=" - $('#applyFilter').closest('form').find('[name=status]').val('on_hold'); - $('#applyFilter').click(); - - " - """, - ), - ( - "cancelled--dot", - _("Completed"), - """ - onclick=" - $('#applyFilter').closest('form').find('[name=status]').val('cancelled'); - $('#applyFilter').click(); - - " - """, - ), - ( - "expired--dot", - _("Expired"), - """ - onclick=" - $('#applyFilter').closest('form').find('[name=status]').val('expired'); - $('#applyFilter').click(); - - " - """, - ), - ] - card_attrs = """ - {redirect} - """ - - -# def projects_tab(request, pk=None): -# """ -# This method is used to projects tab -# """ - -# projects = Project.objects.filter( -# Q(manager=pk) -# | Q(members=pk) -# | Q(task__task_members=pk) -# | Q(task__task_manager=pk) -# ) -# context = {"projects": projects} -# if pk: -# template = "cbv/projects/project_tab.html" -# employees = Employee.objects.filter(id=pk).distinct() -# emoloyee = employees.first() -# context["employee"] = emoloyee -# return render( -# request, -# template, -# context, -# ) - - -class ProjectsTabView(ListView): - model = Project - template_name = "cbv/projects/project_tab.html" - context_object_name = "projects" - - def get_queryset(self): - pk = self.kwargs.get("pk") - queryset = Project.objects.filter( - Q(manager=pk) - | Q(members=pk) - | Q(task__task_members=pk) - | Q(task__task_manager=pk) - ) - return queryset.distinct() - - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - pk = self.kwargs.get("pk") - if pk: - employees = Employee.objects.filter(id=pk).distinct() - employee = employees.first() - context["employee"] = employee - return context - - -# Remove the command lines after horilla converted into CBV -# from employee.cbv.employee_profile import EmployeeProfileView -# EmployeeProfileView.add_tab( -# tabs=[ -# { -# "title": "Projects", -# # "view": projects_tab, -# "view": ProjectsTabView.as_view(), -# "accessibility": "employee.cbv.accessibility.workshift_accessibility", -# }, -# ] -# ) +""" +CBV of projects page +""" + +from typing import Any + +from django.contrib import messages +from django.db.models import Q +from django.http import HttpResponse +from django.urls import reverse +from django.utils.decorators import method_decorator +from django.utils.translation import gettext_lazy as _ +from django.views.generic import ListView + +from employee.models import Employee +from horilla.horilla_middlewares import _thread_locals +from horilla_views.cbv_methods import login_required, permission_required +from horilla_views.generic.cbv.views import ( + HorillaCardView, + HorillaFormView, + HorillaListView, + HorillaNavView, + TemplateView, +) +from project.cbv.cbv_decorators import is_projectmanager_or_member_or_perms +from project.filters import ProjectFilter +from project.forms import ProjectForm +from project.methods import ( + any_project_manager, + any_project_member, + is_project_manager_or_super_user, + you_dont_have_permission, +) +from project.models import Project + + +@method_decorator(login_required, name="dispatch") +@method_decorator( + is_projectmanager_or_member_or_perms("project.view_project"), name="dispatch" +) +class ProjectsView(TemplateView): + """ + for projects page + """ + + template_name = "cbv/projects/projects.html" + + +@method_decorator(login_required, name="dispatch") +@method_decorator( + is_projectmanager_or_member_or_perms("project.view_project"), name="dispatch" +) +class ProjectsNavView(HorillaNavView): + """ + Nav bar + """ + + template_name = "cbv/projects/project_nav.html" + + def __init__(self, **kwargs: Any) -> None: + super().__init__(**kwargs) + self.search_url = reverse("project-list-view") + # self.search_in = [ + # ("status", _("Managers")), + # ("members", _("Members")), + # ] + if self.request.user.has_perm("project.view_project"): + self.actions = [ + { + "action": _("Import"), + "attrs": """ + id="importProject" + data-toggle="oh-modal-toggle" + data-target="#projectImport" + style="cursor: pointer;" + """, + }, + { + "action": _("Export"), + "attrs": """ + id="exportProject" + style="cursor: pointer;" + """, + }, + { + "action": _("Archive"), + "attrs": """ + id="archiveProject" + style="cursor: pointer;" + """, + }, + { + "action": _("Un-archive"), + "attrs": """ + id="unArchiveProject" + style="cursor: pointer;" + """, + }, + { + "action": _("Delete"), + "attrs": """ + class="oh-dropdown__link--danger" + data-action ="delete" + id="deleteProject" + style="cursor: pointer; color:red !important" + """, + }, + ] + self.view_types = [ + { + "type": "list", + "icon": "list-outline", + "url": reverse("project-list-view"), + "attrs": """ + title ='List' + """, + }, + { + "type": "card", + "icon": "grid-outline", + "url": reverse("project-card-view"), + "attrs": """ + title ='Card' + """, + }, + ] + if self.request.user.has_perm("project.add_project"): + self.create_attrs = f""" + onclick = "event.stopPropagation();" + data-toggle="oh-modal-toggle" + data-target="#genericModal" + hx-target="#genericModalBody" + hx-get="{reverse('create-project')}" + """ + + group_by_fields = [ + ("status", _("Status")), + ("is_active", _("Is active")), + ] + nav_title = _("Projects") + filter_instance = ProjectFilter() + filter_form_context_name = "form" + filter_body_template = "cbv/projects/filter.html" + search_swap_target = "#listContainer" + + +@method_decorator(login_required, name="dispatch") +@method_decorator( + is_projectmanager_or_member_or_perms("project.view_project"), name="dispatch" +) +class ProjectsList(HorillaListView): + """ + Projects list view + """ + + def get_queryset(self): + queryset = super().get_queryset() + if not self.request.user.has_perm("project.view_project"): + employee = self.request.user.employee_get + task_filter = queryset.filter( + Q(task__task_members=employee) | Q(task__task_managers=employee) + ) + project_filter = queryset.filter(Q(managers=employee) | Q(members=employee)) + queryset = task_filter | project_filter + return queryset.distinct() + + def __init__(self, **kwargs: Any) -> None: + super().__init__(**kwargs) + self.search_url = reverse("project-list-view") + if self.request.user.is_superuser: + self.action_method = "actions" + + model = Project + filter_class = ProjectFilter + + columns = [ + (_("Project"), "title"), + (_("Project Managers"), "get_managers"), + (_("Project Members"), "get_members"), + (_("Status"), "status_column"), + (_("Start Date"), "start_date"), + (_("End Date"), "end_date"), + (_("File"), "get_document_html"), + (_("Description"), "get_description"), + ] + + sortby_mapping = [ + ("Project", "title"), + ("Start Date", "start_date"), + ("End Date", "end_date"), + ] + + row_status_indications = [ + ( + "new--dot", + _("New"), + """ + onclick=" + $('#applyFilter').closest('form').find('[name=status]').val('new'); + $('#applyFilter').click(); + " + """, + ), + ( + "in-progress--dot", + _("In progress"), + """ + onclick=" + $('#applyFilter').closest('form').find('[name=status]').val('in_progress'); + $('#applyFilter').click(); + + " + """, + ), + ( + "completed--dot", + _("Completed"), + """ + onclick=" + $('#applyFilter').closest('form').find('[name=status]').val('completed'); + $('#applyFilter').click(); + + " + """, + ), + ( + "on-hold--dot", + _("On Hold"), + """ + onclick=" + $('#applyFilter').closest('form').find('[name=status]').val('on_hold'); + $('#applyFilter').click(); + + " + """, + ), + ( + "cancelled--dot", + _("Completed"), + """ + onclick=" + $('#applyFilter').closest('form').find('[name=status]').val('cancelled'); + $('#applyFilter').click(); + + " + """, + ), + ( + "expired--dot", + _("Expired"), + """ + onclick=" + $('#applyFilter').closest('form').find('[name=status]').val('expired'); + $('#applyFilter').click(); + + " + """, + ), + ] + + row_status_class = "status-{status}" + + row_attrs = """ + {redirect} + """ + + +@method_decorator(login_required, name="dispatch") +# @method_decorator(permission_required("project.add_project"), name="dispatch") +class ProjectFormView(HorillaFormView): + """ + form view for create project + """ + + form_class = ProjectForm + model = Project + new_display_title = _("Create Project") + + def __init__(self, **kwargs): + super().__init__(**kwargs) + user = self.request.user + + if not user.is_superuser and not user.has_perm("project.add_project"): + self.template_name = "decorator_404.html" + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + if self.form.instance.pk: + self.form_class.verbose_name = _("Update project") + return context + + def form_valid(self, form: ProjectForm) -> HttpResponse: + if form.is_valid(): + if form.instance.pk: + message = _(f"{self.form.instance} Updated") + HTTP_REFERER = self.request.META.get("HTTP_REFERER", None) + if HTTP_REFERER and "task-view/" in HTTP_REFERER: + form.save() + messages.success(self.request, message) + return self.HttpResponse( + "" + ) + else: + message = _("New project created") + form.save() + messages.success(self.request, _(message)) + return self.HttpResponse() + return super().form_valid(form) + + +class DynamicProjectCreationFormView(ProjectFormView): + + is_dynamic_create_view = True + + +@method_decorator(login_required, name="dispatch") +@method_decorator( + is_projectmanager_or_member_or_perms("project.view_project"), name="dispatch" +) +class ProjectCardView(HorillaCardView): + """ + For card view + """ + + model = Project + filter_class = ProjectFilter + + def get_queryset(self): + queryset = super().get_queryset() + if not self.request.user.has_perm("project.view_project"): + employee = self.request.user.employee_get + task_filter = queryset.filter( + Q(task__task_members=employee) | Q(task__task_managers=employee) + ) + project_filter = queryset.filter(Q(managers=employee) | Q(members=employee)) + queryset = task_filter | project_filter + return queryset.distinct() + + def __init__(self, **kwargs: Any) -> None: + super().__init__(**kwargs) + self.search_url = reverse("project-card-view") + if ( + self.request.user.has_perm("project.change_project") + or self.request.user.has_perm("project.delete_project") + or any_project_manager(self.request.user) + or any_project_member(self.request.user) + ): + self.actions = [ + { + "action": "Edit", + "accessibility": "project.cbv.accessibility.project_manager_accessibility", + "attrs": """ + hx-get='{get_update_url}' + hx-target='#genericModalBody' + data-toggle="oh-modal-toggle" + data-target="#genericModal" + class="oh-dropdown__link" + """, + }, + { + "action": "archive_status", + "accessibility": "project.cbv.accessibility.project_manager_accessibility", + "attrs": """ + href="{get_archive_url}" + onclick="return confirm('Do you want to {archive_status} this project?')" + class="oh-dropdown__link" + """, + }, + { + "action": "Delete", + "accessibility": "project.cbv.accessibility.project_manager_accessibility", + "attrs": """ + onclick=" + event.stopPropagation() + deleteItem({get_delete_url}); + " + class="oh-dropdown__link oh-dropdown__link--danger" + """, + }, + ] + + details = { + "image_src": "get_avatar", + "title": "{get_task_badge_html}", + "subtitle": "Status : {status_column}
Start date : {start_date}
End date : {end_date}", + } + card_status_class = "status-{status}" + + card_status_indications = [ + ( + "new--dot", + _("New"), + """ + onclick=" + $('#applyFilter').closest('form').find('[name=status]').val('new'); + $('#applyFilter').click(); + " + """, + ), + ( + "in-progress--dot", + _("In progress"), + """ + onclick=" + $('#applyFilter').closest('form').find('[name=status]').val('in_progress'); + $('#applyFilter').click(); + + " + """, + ), + ( + "completed--dot", + _("Completed"), + """ + onclick=" + $('#applyFilter').closest('form').find('[name=status]').val('completed'); + $('#applyFilter').click(); + + " + """, + ), + ( + "on-hold--dot", + _("On Hold"), + """ + onclick=" + $('#applyFilter').closest('form').find('[name=status]').val('on_hold'); + $('#applyFilter').click(); + + " + """, + ), + ( + "cancelled--dot", + _("Completed"), + """ + onclick=" + $('#applyFilter').closest('form').find('[name=status]').val('cancelled'); + $('#applyFilter').click(); + + " + """, + ), + ( + "expired--dot", + _("Expired"), + """ + onclick=" + $('#applyFilter').closest('form').find('[name=status]').val('expired'); + $('#applyFilter').click(); + + " + """, + ), + ] + card_attrs = """ + {redirect} + """ + + +# def projects_tab(request, pk=None): +# """ +# This method is used to projects tab +# """ + +# projects = Project.objects.filter( +# Q(manager=pk) +# | Q(members=pk) +# | Q(task__task_members=pk) +# | Q(task__task_manager=pk) +# ) +# context = {"projects": projects} +# if pk: +# template = "cbv/projects/project_tab.html" +# employees = Employee.objects.filter(id=pk).distinct() +# emoloyee = employees.first() +# context["employee"] = emoloyee +# return render( +# request, +# template, +# context, +# ) + + +class ProjectsTabView(ListView): + model = Project + template_name = "cbv/projects/project_tab.html" + context_object_name = "projects" + + def get_queryset(self): + pk = self.kwargs.get("pk") + queryset = Project.objects.filter( + Q(manager=pk) + | Q(members=pk) + | Q(task__task_members=pk) + | Q(task__task_manager=pk) + ) + return queryset.distinct() + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + pk = self.kwargs.get("pk") + if pk: + employees = Employee.objects.filter(id=pk).distinct() + employee = employees.first() + context["employee"] = employee + return context + + +# Remove the command lines after horilla converted into CBV +# from employee.cbv.employee_profile import EmployeeProfileView +# EmployeeProfileView.add_tab( +# tabs=[ +# { +# "title": "Projects", +# # "view": projects_tab, +# "view": ProjectsTabView.as_view(), +# "accessibility": "employee.cbv.accessibility.workshift_accessibility", +# }, +# ] +# ) diff --git a/project/cbv/tasks.py b/project/cbv/tasks.py index c1a22c7fb..7d781cde0 100644 --- a/project/cbv/tasks.py +++ b/project/cbv/tasks.py @@ -1,585 +1,585 @@ -""" -This page handles the cbv methods for task page -""" - -import logging -from typing import Any - -from django import forms -from django.contrib import messages -from django.db.models import Q -from django.http import HttpResponse -from django.shortcuts import render -from django.urls import reverse -from django.utils.decorators import method_decorator -from django.utils.translation import gettext_lazy as _ - -from base.methods import get_subordinates -from horilla_views.cbv_methods import login_required -from horilla_views.generic.cbv.views import ( - HorillaCardView, - HorillaDetailedView, - HorillaFormView, - HorillaListView, - HorillaNavView, - TemplateView, -) -from project.cbv.project_stage import StageDynamicCreateForm -from project.cbv.projects import DynamicProjectCreationFormView -from project.filters import TaskAllFilter -from project.forms import TaskAllForm -from project.methods import you_dont_have_permission -from project.models import Project, ProjectStage, Task -from project.templatetags.taskfilters import task_crud_perm - -logger = logging.getLogger(__name__) - - -@method_decorator(login_required, name="dispatch") -class TasksTemplateView(TemplateView): - """ - view page of the task page - """ - - template_name = "cbv/tasks/task_template_view.html" - - -@method_decorator(login_required, name="dispatch") -class TaskListView(HorillaListView): - """ - list view of the page - """ - - model = Task - filter_class = TaskAllFilter - - def __init__(self, **kwargs: Any) -> None: - super().__init__(**kwargs) - self.view_id = "task-list-container" - self.search_url = reverse("tasks-list-view") - - def get_queryset(self): - queryset = super().get_queryset() - if not self.request.user.has_perm("project.view_task"): - employee_id = self.request.user.employee_get - subordinates = get_subordinates(self.request) - subordinate_ids = [subordinate.id for subordinate in subordinates] - project = queryset.filter( - Q(project__managers=employee_id) - | Q(project__members=employee_id) - | Q(project__managers__in=subordinate_ids) - | Q(project__members__in=subordinate_ids) - ) - queryset = ( - queryset.filter( - Q(task_members=employee_id) - | Q(task_managers=employee_id) - | Q(task_members__in=subordinate_ids) - | Q(task_managers__in=subordinate_ids) - ) - | project - ) - return queryset.distinct() - - columns = [ - (_("Task"), "title"), - (_("Project"), "project"), - (_("Stage"), "stage"), - (_("Mangers"), "get_managers"), - (_("Members"), "get_members"), - (_("End Date"), "end_date"), - (_("Status"), "status_column"), - (_("Description"), "description"), - ] - - sortby_mapping = [ - ("Task", "title"), - ("Project", "project__title"), - ("Stage", "stage"), - ("End Date", "end_date"), - ("Status", "status"), - ] - - action_method = "actions" - - row_status_indications = [ - ( - "todo--dot", - _("To Do"), - """ - onclick=" - $('#applyFilter').closest('form').find('[name=status]').val('to_do'); - $('#applyFilter').click(); - " - """, - ), - ( - "in-progress--dot", - _("In progress"), - """ - onclick=" - $('#applyFilter').closest('form').find('[name=status]').val('in_progress'); - $('#applyFilter').click(); - - " - """, - ), - ( - "completed--dot", - _("Completed"), - """ - onclick=" - $('#applyFilter').closest('form').find('[name=status]').val('completed'); - $('#applyFilter').click(); - - " - """, - ), - ( - "expired--dot", - _("Expired"), - """ - onclick=" - $('#applyFilter').closest('form').find('[name=status]').val('expired'); - $('#applyFilter').click(); - - " - """, - ), - ] - - row_status_class = "status-{status}" - - row_attrs = """ - hx-get='{task_detail_view}?instance_ids={ordered_ids}' - hx-target="#genericModalBody" - data-target="#genericModal" - data-toggle="oh-modal-toggle" - """ - - -@method_decorator(login_required, name="dispatch") -class TasksNavBar(HorillaNavView): - """ - navbar of teh page - """ - - nav_title = _("Tasks") - filter_instance = TaskAllFilter() - filter_form_context_name = "form" - filter_body_template = "cbv/tasks/task_filter.html" - search_swap_target = "#listContainer" - - def __init__(self, **kwargs: Any) -> None: - super().__init__(**kwargs) - employee = self.request.user.employee_get - projects = Project.objects.all() - managers = [ - manager for project in projects for manager in project.managers.all() - ] - members = [member for project in projects for member in project.members.all()] - self.search_url = reverse("tasks-list-view") - if employee in managers + members or self.request.user.has_perm( - "project.add_task" - ): - self.create_attrs = f""" - onclick = "event.stopPropagation();" - data-toggle="oh-modal-toggle" - data-target="#genericModal" - hx-target="#genericModalBody" - hx-get="{reverse('create-task-all')}" - """ - - self.view_types = [ - { - "type": "list", - "icon": "list-outline", - "url": reverse("tasks-list-view"), - "attrs": """ - title ='List' - """, - }, - { - "type": "card", - "icon": "grid-outline", - "url": reverse("tasks-card-view"), - "attrs": """ - title ='Card' - """, - }, - ] - - if self.request.user.has_perm("project.view_task"): - self.actions = [ - { - "action": _("Archive"), - "attrs": """ - id="archiveTask", - style="cursor: pointer;" - """, - }, - { - "action": _("Un-Archive"), - "attrs": """ - id="unArchiveTask", - style="cursor: pointer;" - """, - }, - { - "action": _("Delete"), - "attrs": """ - class="oh-dropdown__link--danger" - data-action = "delete" - id="deleteTask" - style="cursor: pointer; color:red !important" - - """, - }, - ] - - group_by_fields = [ - ("project", _("Project")), - ("stage", _("Stage")), - ("status", _("Status")), - ] - - -@method_decorator(login_required, name="dispatch") -class TaskCreateForm(HorillaFormView): - """ - Form view for create and update tasks - """ - - form_class = TaskAllForm - model = Task - template_name = "cbv/tasks/task_form.html" - new_display_title = _("Create Task") - - def __init__(self, **kwargs: Any) -> None: - super().__init__(**kwargs) - if self.request.user.has_perm("project.view_task"): - self.dynamic_create_fields = [ - ("project", DynamicProjectCreationFormView), - ("stage", StageDynamicCreateForm, ["project"]), - ] - - def get(self, request, *args, pk=None, **kwargs): - project_id = self.kwargs.get("project_id") - stage_id = self.kwargs.get("stage_id") - task_id = self.kwargs.get("pk") - try: - if project_id: - project = Project.objects.filter(id=project_id).first() - elif stage_id: - project = ProjectStage.objects.filter(id=stage_id).first().project - elif task_id: - task = Task.objects.filter(id=task_id).first() - project = task.project - elif not task_id: - return super().get(request, *args, pk=pk, **kwargs) - if ( - request.user.employee_get in project.managers.all() - or request.user.is_superuser - ): - self.dynamic_create_fields = [ - ("project", DynamicProjectCreationFormView), - ("stage", StageDynamicCreateForm), - ] - return super().get(request, *args, pk=pk, **kwargs) - elif task_id: - if request.user.employee_get in task.task_managers.all(): - return super().get(request, *args, pk=pk, **kwargs) - - else: - return you_dont_have_permission(request) - except Exception as e: - logger.error(e) - messages.error(request, _("Something went wrong!")) - return HttpResponse("") - - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - project_id = self.kwargs.get("project_id") - stage_id = self.kwargs.get("stage_id") - task_id = self.kwargs.get("pk") - - dynamic_project_id = self.request.GET.get("dynamic_project") - - if dynamic_project_id and dynamic_project_id != "dynamic_create": - stages = ProjectStage.objects.filter(project=dynamic_project_id) - attrs = self.form.fields["stage"].widget.attrs - attrs["style"] = "width:100% !important;" - self.form.fields["stage"].choices = ( - [("", _("Select Stage"))] - + [(stage.pk, stage) for stage in stages] - + [("dynamic_create", _("Dynamic Create"))] - ) - - if task_id and not dynamic_project_id: - task = self.form.instance - stages = task.project.project_stages.all() - self.form.fields["stage"].choices = ( - [("", _("Select Stage"))] - + [(stage.pk, stage) for stage in stages] - + [("dynamic_create", _("Dynamic Create"))] - ) - - if stage_id: - stage = ProjectStage.objects.filter(id=stage_id).first() - project = stage.project - self.form.fields["stage"].initial = stage - self.form.fields["stage"].choices = [(stage.id, stage.title)] - self.form.fields["project"].initial = project - self.form.fields["project"].choices = [(project.id, project.title)] - elif project_id: - project = Project.objects.get(id=project_id) - self.form.fields["project"].initial = project - self.form.fields["project"].choices = [(project.id, project.title)] - stages = ProjectStage.objects.filter(project=project) - self.form.fields["stage"].choices = [ - (stage.id, stage.title) for stage in stages - ] - elif self.form.instance.pk: - self.form_class.verbose_name = _("Update Task") - if self.request.GET.get("project_task"): - self.form.fields["project"].widget = forms.HiddenInput() - self.form.fields["stage"].widget = forms.HiddenInput() - else: - if self.request.user.is_superuser: - self.dynamic_create_fields = [ - ("project", DynamicProjectCreationFormView), - ("stage", StageDynamicCreateForm, ["project"]), - ] - - if project_id or stage_id: - if ( - self.request.user.employee_get in project.managers.all() - or self.request.user.is_superuser - ): - - self.form.fields["project"].choices.append( - ("dynamic_create", "Dynamic create") - ) - self.form.fields["stage"].choices.append( - ("dynamic_create", "Dynamic create") - ) - - return context - - def form_valid(self, form: TaskAllForm) -> HttpResponse: - stage_id = self.kwargs.get("stage_id") - if form.is_valid(): - if form.instance.pk: - message = _(f"{self.form.instance} Updated") - else: - message = _("New Task created") - form.save() - messages.success(self.request, _(message)) - if stage_id or self.request.GET.get("project_task"): - return HttpResponse("") - return self.HttpResponse("") - return super().form_valid(form) - - -class DynamicTaskCreateFormView(TaskCreateForm): - - is_dynamic_create_view = True - - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - if self.request.GET: - project_id = self.request.GET.get("project_id") - if project_id: - project = Project.objects.get(id=project_id) - stages = ProjectStage.objects.filter(project__id=project_id) - self.form.fields["project"].initial = project - self.form.fields["project"].choices = [(project.id, project.title)] - self.form.fields["stage"].queryset = stages - # self.form.fields["project"].widget = forms.HiddenInput() - return context - - -@method_decorator(login_required, name="dispatch") -class TaskDetailView(HorillaDetailedView): - """ - detail view of the task page - """ - - model = Task - title = _("Task Details") - - header = {"title": "title", "subtitle": "project", "avatar": "get_avatar"} - - body = [ - (_("Task"), "title"), - (_("Project"), "project"), - (_("Stage"), "stage"), - (_("Task Mangers"), "get_managers"), - (_("Task Members"), "get_members"), - (_("Status"), "status_column"), - (_("End Date"), "end_date"), - (_("Description"), "description"), - (_("Document"), "document_col", True), - ] - - action_method = "detail_view_actions" - - -@method_decorator(login_required, name="dispatch") -class TaskCardView(HorillaCardView): - """ - card view of the page - """ - - model = Task - filter_class = TaskAllFilter - - def __init__(self, **kwargs: Any) -> None: - super().__init__(**kwargs) - self.view_id = "task-card" - self.search_url = reverse("tasks-card-view") - self.actions = [ - { - "action": _("Edit"), - "accessibility": "project.cbv.accessibility.task_crud_accessibility", - "attrs": """ - data-toggle = "oh-modal-toggle" - data-target = "#genericModal" - hx-target="#genericModalBody" - hx-get ='{get_update_url}' - class="oh-dropdown__link" - style="cursor: pointer;" - """, - }, - { - "action": _("archive_status"), - "accessibility": "project.cbv.accessibility.task_crud_accessibility", - "attrs": """ - href="{get_archive_url}" - onclick="return confirm('Do you want to {archive_status} this task?')" - class="oh-dropdown__link" - """, - }, - { - "action": _("Delete"), - "accessibility": "project.cbv.accessibility.task_crud_accessibility", - "attrs": """ - onclick=" - event.stopPropagation() - deleteItem({get_delete_url}); - " - class="oh-dropdown__link oh-dropdown__link--danger" - """, - }, - ] - - def get_queryset(self): - queryset = super().get_queryset() - if not self.request.user.has_perm("project.view_task"): - employee_id = self.request.user.employee_get - subordinates = get_subordinates(self.request) - subordinate_ids = [subordinate.id for subordinate in subordinates] - project = queryset.filter( - Q(project__managers=employee_id) - | Q(project__members=employee_id) - | Q(project__managers__in=subordinate_ids) - | Q(project__members__in=subordinate_ids) - ) - queryset = ( - queryset.filter( - Q(task_members=employee_id) - | Q(task_managers=employee_id) - | Q(task_members__in=subordinate_ids) - | Q(task_managers__in=subordinate_ids) - ) - | project - ) - return queryset.distinct() - - details = { - "image_src": "get_avatar", - "title": "{title}", - "subtitle": "Project Name : {if_project}
Stage Name : {stage}
End Date : {end_date}", - } - - card_attrs = """ - hx-get='{task_detail_view}?instance_ids={ordered_ids}' - hx-target="#genericModalBody" - data-target="#genericModal" - data-toggle="oh-modal-toggle" - """ - - card_status_indications = [ - ( - "todo--dot", - _("To Do"), - """ - onclick=" - $('#applyFilter').closest('form').find('[name=status]').val('to_do'); - $('#applyFilter').click(); - " - """, - ), - ( - "in-progress--dot", - _("In progress"), - """ - onclick=" - $('#applyFilter').closest('form').find('[name=status]').val('in_progress'); - $('#applyFilter').click(); - - " - """, - ), - ( - "completed--dot", - _("Completed"), - """ - onclick=" - $('#applyFilter').closest('form').find('[name=status]').val('completed'); - $('#applyFilter').click(); - - " - """, - ), - ( - "expired--dot", - _("Expired"), - """ - onclick=" - $('#applyFilter').closest('form').find('[name=status]').val('expired'); - $('#applyFilter').click(); - - " - """, - ), - ] - - card_status_class = "status-{status}" - - -class TasksInIndividualView(TaskListView): - - def __init__(self, **kwargs: Any) -> None: - super().__init__(**kwargs) - employee_id = self.request.GET.get("employee_id") - self.row_attrs = f""" - hx-get='{{task_detail_view}}?instance_ids={{ordered_ids}}&employee_id={employee_id}' - hx-target="#genericModalBody" - data-target="#genericModal" - data-toggle="oh-modal-toggle" - """ - - def get_queryset(self): - queryset = HorillaListView.get_queryset(self) - employee_id = self.request.GET.get("employee_id") - project_id = self.request.GET.get("project_id") - queryset = queryset.filter( - Q(task_members=employee_id) | Q(task_manager=employee_id) - ) - queryset = queryset.filter(project=project_id) - return queryset - - row_status_indications = None - bulk_select_option = None - action_method = None +""" +This page handles the cbv methods for task page +""" + +import logging +from typing import Any + +from django import forms +from django.contrib import messages +from django.db.models import Q +from django.http import HttpResponse +from django.shortcuts import render +from django.urls import reverse +from django.utils.decorators import method_decorator +from django.utils.translation import gettext_lazy as _ + +from base.methods import get_subordinates +from horilla_views.cbv_methods import login_required +from horilla_views.generic.cbv.views import ( + HorillaCardView, + HorillaDetailedView, + HorillaFormView, + HorillaListView, + HorillaNavView, + TemplateView, +) +from project.cbv.project_stage import StageDynamicCreateForm +from project.cbv.projects import DynamicProjectCreationFormView +from project.filters import TaskAllFilter +from project.forms import TaskAllForm +from project.methods import you_dont_have_permission +from project.models import Project, ProjectStage, Task +from project.templatetags.taskfilters import task_crud_perm + +logger = logging.getLogger(__name__) + + +@method_decorator(login_required, name="dispatch") +class TasksTemplateView(TemplateView): + """ + view page of the task page + """ + + template_name = "cbv/tasks/task_template_view.html" + + +@method_decorator(login_required, name="dispatch") +class TaskListView(HorillaListView): + """ + list view of the page + """ + + model = Task + filter_class = TaskAllFilter + + def __init__(self, **kwargs: Any) -> None: + super().__init__(**kwargs) + self.view_id = "task-list-container" + self.search_url = reverse("tasks-list-view") + + def get_queryset(self): + queryset = super().get_queryset() + if not self.request.user.has_perm("project.view_task"): + employee_id = self.request.user.employee_get + subordinates = get_subordinates(self.request) + subordinate_ids = [subordinate.id for subordinate in subordinates] + project = queryset.filter( + Q(project__managers=employee_id) + | Q(project__members=employee_id) + | Q(project__managers__in=subordinate_ids) + | Q(project__members__in=subordinate_ids) + ) + queryset = ( + queryset.filter( + Q(task_members=employee_id) + | Q(task_managers=employee_id) + | Q(task_members__in=subordinate_ids) + | Q(task_managers__in=subordinate_ids) + ) + | project + ) + return queryset.distinct() + + columns = [ + (_("Task"), "title"), + (_("Project"), "project"), + (_("Stage"), "stage"), + (_("Mangers"), "get_managers"), + (_("Members"), "get_members"), + (_("End Date"), "end_date"), + (_("Status"), "status_column"), + (_("Description"), "description"), + ] + + sortby_mapping = [ + ("Task", "title"), + ("Project", "project__title"), + ("Stage", "stage"), + ("End Date", "end_date"), + ("Status", "status"), + ] + + action_method = "actions" + + row_status_indications = [ + ( + "todo--dot", + _("To Do"), + """ + onclick=" + $('#applyFilter').closest('form').find('[name=status]').val('to_do'); + $('#applyFilter').click(); + " + """, + ), + ( + "in-progress--dot", + _("In progress"), + """ + onclick=" + $('#applyFilter').closest('form').find('[name=status]').val('in_progress'); + $('#applyFilter').click(); + + " + """, + ), + ( + "completed--dot", + _("Completed"), + """ + onclick=" + $('#applyFilter').closest('form').find('[name=status]').val('completed'); + $('#applyFilter').click(); + + " + """, + ), + ( + "expired--dot", + _("Expired"), + """ + onclick=" + $('#applyFilter').closest('form').find('[name=status]').val('expired'); + $('#applyFilter').click(); + + " + """, + ), + ] + + row_status_class = "status-{status}" + + row_attrs = """ + hx-get='{task_detail_view}?instance_ids={ordered_ids}' + hx-target="#genericModalBody" + data-target="#genericModal" + data-toggle="oh-modal-toggle" + """ + + +@method_decorator(login_required, name="dispatch") +class TasksNavBar(HorillaNavView): + """ + navbar of teh page + """ + + nav_title = _("Tasks") + filter_instance = TaskAllFilter() + filter_form_context_name = "form" + filter_body_template = "cbv/tasks/task_filter.html" + search_swap_target = "#listContainer" + + def __init__(self, **kwargs: Any) -> None: + super().__init__(**kwargs) + employee = self.request.user.employee_get + projects = Project.objects.all() + managers = [ + manager for project in projects for manager in project.managers.all() + ] + members = [member for project in projects for member in project.members.all()] + self.search_url = reverse("tasks-list-view") + if employee in managers + members or self.request.user.has_perm( + "project.add_task" + ): + self.create_attrs = f""" + onclick = "event.stopPropagation();" + data-toggle="oh-modal-toggle" + data-target="#genericModal" + hx-target="#genericModalBody" + hx-get="{reverse('create-task-all')}" + """ + + self.view_types = [ + { + "type": "list", + "icon": "list-outline", + "url": reverse("tasks-list-view"), + "attrs": """ + title ='List' + """, + }, + { + "type": "card", + "icon": "grid-outline", + "url": reverse("tasks-card-view"), + "attrs": """ + title ='Card' + """, + }, + ] + + if self.request.user.has_perm("project.view_task"): + self.actions = [ + { + "action": _("Archive"), + "attrs": """ + id="archiveTask", + style="cursor: pointer;" + """, + }, + { + "action": _("Un-Archive"), + "attrs": """ + id="unArchiveTask", + style="cursor: pointer;" + """, + }, + { + "action": _("Delete"), + "attrs": """ + class="oh-dropdown__link--danger" + data-action = "delete" + id="deleteTask" + style="cursor: pointer; color:red !important" + + """, + }, + ] + + group_by_fields = [ + ("project", _("Project")), + ("stage", _("Stage")), + ("status", _("Status")), + ] + + +@method_decorator(login_required, name="dispatch") +class TaskCreateForm(HorillaFormView): + """ + Form view for create and update tasks + """ + + form_class = TaskAllForm + model = Task + template_name = "cbv/tasks/task_form.html" + new_display_title = _("Create Task") + + def __init__(self, **kwargs: Any) -> None: + super().__init__(**kwargs) + if self.request.user.has_perm("project.view_task"): + self.dynamic_create_fields = [ + ("project", DynamicProjectCreationFormView), + ("stage", StageDynamicCreateForm, ["project"]), + ] + + def get(self, request, *args, pk=None, **kwargs): + project_id = self.kwargs.get("project_id") + stage_id = self.kwargs.get("stage_id") + task_id = self.kwargs.get("pk") + try: + if project_id: + project = Project.objects.filter(id=project_id).first() + elif stage_id: + project = ProjectStage.objects.filter(id=stage_id).first().project + elif task_id: + task = Task.objects.filter(id=task_id).first() + project = task.project + elif not task_id: + return super().get(request, *args, pk=pk, **kwargs) + if ( + request.user.employee_get in project.managers.all() + or request.user.is_superuser + ): + self.dynamic_create_fields = [ + ("project", DynamicProjectCreationFormView), + ("stage", StageDynamicCreateForm), + ] + return super().get(request, *args, pk=pk, **kwargs) + elif task_id: + if request.user.employee_get in task.task_managers.all(): + return super().get(request, *args, pk=pk, **kwargs) + + else: + return you_dont_have_permission(request) + except Exception as e: + logger.error(e) + messages.error(request, _("Something went wrong!")) + return HttpResponse("") + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + project_id = self.kwargs.get("project_id") + stage_id = self.kwargs.get("stage_id") + task_id = self.kwargs.get("pk") + + dynamic_project_id = self.request.GET.get("dynamic_project") + + if dynamic_project_id and dynamic_project_id != "dynamic_create": + stages = ProjectStage.objects.filter(project=dynamic_project_id) + attrs = self.form.fields["stage"].widget.attrs + attrs["style"] = "width:100% !important;" + self.form.fields["stage"].choices = ( + [("", _("Select Stage"))] + + [(stage.pk, stage) for stage in stages] + + [("dynamic_create", _("Dynamic Create"))] + ) + + if task_id and not dynamic_project_id: + task = self.form.instance + stages = task.project.project_stages.all() + self.form.fields["stage"].choices = ( + [("", _("Select Stage"))] + + [(stage.pk, stage) for stage in stages] + + [("dynamic_create", _("Dynamic Create"))] + ) + + if stage_id: + stage = ProjectStage.objects.filter(id=stage_id).first() + project = stage.project + self.form.fields["stage"].initial = stage + self.form.fields["stage"].choices = [(stage.id, stage.title)] + self.form.fields["project"].initial = project + self.form.fields["project"].choices = [(project.id, project.title)] + elif project_id: + project = Project.objects.get(id=project_id) + self.form.fields["project"].initial = project + self.form.fields["project"].choices = [(project.id, project.title)] + stages = ProjectStage.objects.filter(project=project) + self.form.fields["stage"].choices = [ + (stage.id, stage.title) for stage in stages + ] + elif self.form.instance.pk: + self.form_class.verbose_name = _("Update Task") + if self.request.GET.get("project_task"): + self.form.fields["project"].widget = forms.HiddenInput() + self.form.fields["stage"].widget = forms.HiddenInput() + else: + if self.request.user.is_superuser: + self.dynamic_create_fields = [ + ("project", DynamicProjectCreationFormView), + ("stage", StageDynamicCreateForm, ["project"]), + ] + + if project_id or stage_id: + if ( + self.request.user.employee_get in project.managers.all() + or self.request.user.is_superuser + ): + + self.form.fields["project"].choices.append( + ("dynamic_create", "Dynamic create") + ) + self.form.fields["stage"].choices.append( + ("dynamic_create", "Dynamic create") + ) + + return context + + def form_valid(self, form: TaskAllForm) -> HttpResponse: + stage_id = self.kwargs.get("stage_id") + if form.is_valid(): + if form.instance.pk: + message = _(f"{self.form.instance} Updated") + else: + message = _("New Task created") + form.save() + messages.success(self.request, _(message)) + if stage_id or self.request.GET.get("project_task"): + return HttpResponse("") + return self.HttpResponse("") + return super().form_valid(form) + + +class DynamicTaskCreateFormView(TaskCreateForm): + + is_dynamic_create_view = True + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + if self.request.GET: + project_id = self.request.GET.get("project_id") + if project_id: + project = Project.objects.get(id=project_id) + stages = ProjectStage.objects.filter(project__id=project_id) + self.form.fields["project"].initial = project + self.form.fields["project"].choices = [(project.id, project.title)] + self.form.fields["stage"].queryset = stages + # self.form.fields["project"].widget = forms.HiddenInput() + return context + + +@method_decorator(login_required, name="dispatch") +class TaskDetailView(HorillaDetailedView): + """ + detail view of the task page + """ + + model = Task + title = _("Task Details") + + header = {"title": "title", "subtitle": "project", "avatar": "get_avatar"} + + body = [ + (_("Task"), "title"), + (_("Project"), "project"), + (_("Stage"), "stage"), + (_("Task Mangers"), "get_managers"), + (_("Task Members"), "get_members"), + (_("Status"), "status_column"), + (_("End Date"), "end_date"), + (_("Description"), "description"), + (_("Document"), "document_col", True), + ] + + action_method = "detail_view_actions" + + +@method_decorator(login_required, name="dispatch") +class TaskCardView(HorillaCardView): + """ + card view of the page + """ + + model = Task + filter_class = TaskAllFilter + + def __init__(self, **kwargs: Any) -> None: + super().__init__(**kwargs) + self.view_id = "task-card" + self.search_url = reverse("tasks-card-view") + self.actions = [ + { + "action": _("Edit"), + "accessibility": "project.cbv.accessibility.task_crud_accessibility", + "attrs": """ + data-toggle = "oh-modal-toggle" + data-target = "#genericModal" + hx-target="#genericModalBody" + hx-get ='{get_update_url}' + class="oh-dropdown__link" + style="cursor: pointer;" + """, + }, + { + "action": _("archive_status"), + "accessibility": "project.cbv.accessibility.task_crud_accessibility", + "attrs": """ + href="{get_archive_url}" + onclick="return confirm('Do you want to {archive_status} this task?')" + class="oh-dropdown__link" + """, + }, + { + "action": _("Delete"), + "accessibility": "project.cbv.accessibility.task_crud_accessibility", + "attrs": """ + onclick=" + event.stopPropagation() + deleteItem({get_delete_url}); + " + class="oh-dropdown__link oh-dropdown__link--danger" + """, + }, + ] + + def get_queryset(self): + queryset = super().get_queryset() + if not self.request.user.has_perm("project.view_task"): + employee_id = self.request.user.employee_get + subordinates = get_subordinates(self.request) + subordinate_ids = [subordinate.id for subordinate in subordinates] + project = queryset.filter( + Q(project__managers=employee_id) + | Q(project__members=employee_id) + | Q(project__managers__in=subordinate_ids) + | Q(project__members__in=subordinate_ids) + ) + queryset = ( + queryset.filter( + Q(task_members=employee_id) + | Q(task_managers=employee_id) + | Q(task_members__in=subordinate_ids) + | Q(task_managers__in=subordinate_ids) + ) + | project + ) + return queryset.distinct() + + details = { + "image_src": "get_avatar", + "title": "{title}", + "subtitle": "Project Name : {if_project}
Stage Name : {stage}
End Date : {end_date}", + } + + card_attrs = """ + hx-get='{task_detail_view}?instance_ids={ordered_ids}' + hx-target="#genericModalBody" + data-target="#genericModal" + data-toggle="oh-modal-toggle" + """ + + card_status_indications = [ + ( + "todo--dot", + _("To Do"), + """ + onclick=" + $('#applyFilter').closest('form').find('[name=status]').val('to_do'); + $('#applyFilter').click(); + " + """, + ), + ( + "in-progress--dot", + _("In progress"), + """ + onclick=" + $('#applyFilter').closest('form').find('[name=status]').val('in_progress'); + $('#applyFilter').click(); + + " + """, + ), + ( + "completed--dot", + _("Completed"), + """ + onclick=" + $('#applyFilter').closest('form').find('[name=status]').val('completed'); + $('#applyFilter').click(); + + " + """, + ), + ( + "expired--dot", + _("Expired"), + """ + onclick=" + $('#applyFilter').closest('form').find('[name=status]').val('expired'); + $('#applyFilter').click(); + + " + """, + ), + ] + + card_status_class = "status-{status}" + + +class TasksInIndividualView(TaskListView): + + def __init__(self, **kwargs: Any) -> None: + super().__init__(**kwargs) + employee_id = self.request.GET.get("employee_id") + self.row_attrs = f""" + hx-get='{{task_detail_view}}?instance_ids={{ordered_ids}}&employee_id={employee_id}' + hx-target="#genericModalBody" + data-target="#genericModal" + data-toggle="oh-modal-toggle" + """ + + def get_queryset(self): + queryset = HorillaListView.get_queryset(self) + employee_id = self.request.GET.get("employee_id") + project_id = self.request.GET.get("project_id") + queryset = queryset.filter( + Q(task_members=employee_id) | Q(task_manager=employee_id) + ) + queryset = queryset.filter(project=project_id) + return queryset + + row_status_indications = None + bulk_select_option = None + action_method = None diff --git a/project/cbv/timesheet.py b/project/cbv/timesheet.py index e4e2d7777..57d9634c3 100644 --- a/project/cbv/timesheet.py +++ b/project/cbv/timesheet.py @@ -1,497 +1,497 @@ -""" -CBV of time sheet page -""" - -from typing import Any - -from django import forms -from django.contrib import messages -from django.db.models import Q -from django.http import HttpResponse -from django.shortcuts import render -from django.urls import resolve, reverse -from django.utils.decorators import method_decorator -from django.utils.translation import gettext_lazy as _ - -from employee.models import Employee -from horilla_views.cbv_methods import login_required -from horilla_views.generic.cbv.views import ( - HorillaCardView, - HorillaDetailedView, - HorillaFormView, - HorillaListView, - HorillaNavView, - TemplateView, -) -from project.cbv.cbv_decorators import is_projectmanager_or_member_or_perms -from project.cbv.projects import DynamicProjectCreationFormView -from project.cbv.tasks import DynamicTaskCreateFormView -from project.filters import TimeSheetFilter -from project.forms import TimeSheetForm -from project.models import Project, Task, TimeSheet - - -@method_decorator(login_required, name="dispatch") -@method_decorator( - is_projectmanager_or_member_or_perms("project.view_timesheet"), name="dispatch" -) -class TimeSheetView(TemplateView): - """ - for time sheet page - """ - - template_name = "cbv/timesheet/timesheet.html" - - -@method_decorator(login_required, name="dispatch") -@method_decorator( - is_projectmanager_or_member_or_perms("project.view_timesheet"), name="dispatch" -) -class TimeSheetNavView(HorillaNavView): - """ - Nav bar - """ - - template_name = "cbv/timesheet/timesheet_nav.html" - - def __init__(self, **kwargs: Any) -> None: - super().__init__(**kwargs) - self.search_url = reverse("time-sheet-list") - url = f"{reverse('personal-time-sheet-view',kwargs={'emp_id': self.request.user.employee_get.id})}" - self.actions = [ - { - "action": _("Delete"), - "attrs": """ - class="oh-dropdown__link--danger" - data-action ="delete" - onclick="deleteTimeSheet();" - style="cursor: pointer; color:red !important" - """, - }, - ] - self.view_types = [ - { - "type": "list", - "icon": "list-outline", - "url": reverse("time-sheet-list"), - "attrs": """ - title ='List' - """, - }, - { - "type": "card", - "icon": "grid-outline", - "url": reverse("time-sheet-card"), - "attrs": """ - title ='Card' - """, - }, - { - "type": "graph", - "icon": "bar-chart", - "attrs": f""" - onclick="event.stopPropagation(); - window.location.href='{url}'" - title ='Graph' - """, - }, - ] - - self.create_attrs = f""" - onclick = "event.stopPropagation();" - data-toggle="oh-modal-toggle" - data-target="#genericModal" - hx-target="#genericModalBody" - hx-get="{reverse('create-time-sheet')}" - """ - - group_by_fields = [ - ("employee_id", _("Employee")), - ("project_id", _("Project")), - ("date", _("Date")), - ("status", _("Status")), - ( - "employee_id__employee_work_info__reporting_manager_id", - _("Reporting Manager"), - ), - ("employee_id__employee_work_info__department_id", _("Department")), - ("employee_id__employee_work_info__job_position_id", _("Job Position")), - ("employee_id__employee_work_info__employee_type_id", _("Employement Type")), - ("employee_id__employee_work_info__company_id", _("Company")), - ] - - nav_title = _("Time Sheet") - filter_instance = TimeSheetFilter() - filter_form_context_name = "form" - filter_body_template = "cbv/timesheet/filter.html" - search_swap_target = "#listContainer" - - -@method_decorator(login_required, name="dispatch") -@method_decorator( - is_projectmanager_or_member_or_perms("project.view_timesheet"), name="dispatch" -) -class TimeSheetList(HorillaListView): - """ - Time sheet list view - """ - - def get_queryset(self): - queryset = super().get_queryset() - if not self.request.user.has_perm("project.view_timesheet"): - employee = self.request.user.employee_get - queryset = queryset.filter( - Q(task_id__task_managers=employee) - | Q(project_id__managers=employee) - | Q(employee_id=employee) - ).distinct() - return queryset - - def __init__(self, **kwargs: Any) -> None: - super().__init__(**kwargs) - - self.search_url = reverse("time-sheet-list") - self.action_method = "actions" - - model = TimeSheet - filter_class = TimeSheetFilter - - columns = [ - (_("Employee"), "employee_id", "employee_id__get_avatar"), - (_("Project"), "project_id"), - (_("Task"), "task_id"), - (_("Date"), "date"), - (_("Time Spent"), "time_spent"), - (_("Status"), "status_column"), - (_("Description"), "description"), - ] - - sortby_mapping = [ - ("Employee", "employee_id__employee_first_name", "employee_id__get_avatar"), - ("Project", "project_id__title"), - ("Task", "task_id__title"), - ("Time Spent", "time_spent"), - ("Date", "date"), - ] - - row_status_indications = [ - ( - "in-progress--dot", - _("In progress"), - """ - onclick=" - $('#applyFilter').closest('form').find('[name=status]').val('in_Progress'); - $('#applyFilter').click(); - - " - """, - ), - ( - "completed--dot", - _("Completed"), - """ - onclick=" - $('#applyFilter').closest('form').find('[name=status]').val('completed'); - $('#applyFilter').click(); - - " - """, - ), - ] - row_attrs = """ - hx-get='{detail_view}?instance_ids={ordered_ids}' - hx-target="#genericModalBody" - data-target="#genericModal" - data-toggle="oh-modal-toggle" - """ - - row_status_class = "status-{status}" - - -@method_decorator(login_required, name="dispatch") -@method_decorator( - is_projectmanager_or_member_or_perms("project.view_timesheet"), name="dispatch" -) -class TaskTimeSheet(TimeSheetList): - - row_attrs = "" - row_status_indications = False - bulk_select_option = False - - def __init__(self, **kwargs: Any) -> None: - super().__init__(**kwargs) - self.view_id = "task-timesheet-container" - task_id = resolve(self.request.path_info).kwargs.get("task_id") - self.request.task_id = task_id - employee_id = self.request.GET.get("employee_id") - if employee_id: - self.action_method = "actions" - - def get_context_data(self, **kwargs: Any): - context = super().get_context_data(**kwargs) - task_id = self.kwargs.get("task_id") - task = Task.objects.get(id=task_id) - project = task.project - context["task_id"] = task_id - context["project"] = project - context["task"] = task - return context - - template_name = "cbv/timesheet/task_timesheet.html" - - def get_queryset(self): - queryset = HorillaListView.get_queryset(self) - task_id = self.kwargs.get("task_id") - task = Task.objects.filter(id=task_id).first() - queryset = TimeSheet.objects.filter(task_id=task_id) - queryset = queryset.filter(task_id=task_id) - employee_id = self.request.GET.get("employee_id") - if employee_id: - employee = Employee.objects.filter(id=employee_id).first() - if ( - not employee in task.task_managers.all() - and not employee in task.project.managers.all() - and not employee.employee_user_id.is_superuser - ): - queryset = queryset.filter(employee_id=employee_id) - - return queryset - - -@method_decorator(login_required, name="dispatch") -@method_decorator( - is_projectmanager_or_member_or_perms("project.view_timesheet"), name="dispatch" -) -class TimeSheetFormView(HorillaFormView): - """ - form view for create project - """ - - def __init__(self, **kwargs: Any) -> None: - super().__init__(**kwargs) - self.dynamic_create_fields = [ - ("task_id", DynamicTaskCreateFormView), - ] - if self.request.user.has_perm("project.add_project"): - self.dynamic_create_fields.append( - ("project_id", DynamicProjectCreationFormView) - ) - - form_class = TimeSheetForm - model = TimeSheet - new_display_title = _("Create Time Sheet") - # template_name = "cbv/timesheet/form.html" - - def get_initial(self) -> dict: - initial = super().get_initial() - task_id = self.kwargs.get("task_id") - if task_id: - task = Task.objects.get(id=task_id) - project_id = task.project - initial["project_id"] = project_id.id - initial["task_id"] = task.id - return initial - - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - task_id = self.kwargs.get("task_id") - user_employee_id = self.request.user.employee_get.id - project = None - if task_id: - task = Task.objects.get(id=task_id) - project = task.project - employee = Employee.objects.filter(id=user_employee_id) - - if self.form.instance.pk: - task_id = self.form.instance.task_id.id - project = self.form.instance.project_id - tasks = Task.objects.filter(project=project) - employee = Employee.objects.filter(id=user_employee_id) - task = Task.objects.get(id=task_id) - self.form.fields["task_id"].queryset = tasks - self.form.fields["task_id"].choices = [ - (item.id, item.title) for item in tasks - ] - self.form.fields["task_id"].choices.append( - ("dynamic_create", "Dynamic create") - ) - task_id = self.request.GET.get("task_id") - self.form_class.verbose_name = _("Update Time Sheet") - # If the timesheet create from task or project - if project: - if self.request.user.is_superuser or self.request.user.has_perm( - "project.add_project" - ): - members = ( - project.managers.all() - | project.members.all() - | task.task_members.all() - | task.task_managers.all() - ).distinct() - elif employee.first() in project.managers.all(): - members = ( - employee - | project.members.all() - | task.task_members.all() - | task.task_managers.all() - ).distinct() - elif employee.first() in task.task_managers.all(): - members = (employee | task.task_members.all()).distinct() - else: - members = employee - if task_id: - self.form.fields["project_id"].widget = forms.HiddenInput() - self.form.fields["task_id"].widget = forms.HiddenInput() - self.form.fields["employee_id"].queryset = members - - # If the timesheet create directly - else: - employee = self.request.user.employee_get - if self.request.user.has_perm("project.add_timesheet"): - projects = Project.objects.all() - else: - projects = ( - Project.objects.filter(managers=employee) - | Project.objects.filter(members=employee) - | Project.objects.filter( - id__in=Task.objects.filter(task_managers=employee).values_list( - "project", flat=True - ) - ) - | Project.objects.filter( - id__in=Task.objects.filter(task_members=employee).values_list( - "project", flat=True - ) - ) - ).distinct() - self.form.fields["project_id"].queryset = projects - return context - - def form_valid(self, form: TimeSheetForm) -> HttpResponse: - if form.is_valid(): - if form.instance.pk: - message = _(f"{self.form.instance} Updated") - else: - message = _("New time sheet created") - form.save() - messages.success(self.request, _(message)) - return self.HttpResponse() - return super().form_valid(form) - - -@method_decorator(login_required, name="dispatch") -@method_decorator( - is_projectmanager_or_member_or_perms("project.view_timesheet"), name="dispatch" -) -class TimeSheetCardView(HorillaCardView): - """ - For card view - """ - - model = TimeSheet - filter_class = TimeSheetFilter - - def get_queryset(self): - queryset = super().get_queryset() - if not self.request.user.has_perm("project.view_timesheet"): - employee = self.request.user.employee_get - queryset = queryset.filter( - Q(task_id__task_managers=employee) - | Q(project_id__managers=employee) - | Q(employee_id=employee) - ).distinct() - return queryset - - def __init__(self, **kwargs: Any) -> None: - super().__init__(**kwargs) - self.search_url = reverse("time-sheet-card") - self.actions = [ - { - "action": "Edit", - "attrs": """ - hx-get='{get_update_url}' - hx-target='#genericModalBody' - data-toggle="oh-modal-toggle" - data-target="#genericModal" - class="oh-dropdown__link" - """, - }, - { - "action": "Delete", - "attrs": """ - onclick=" - event.stopPropagation() - deleteItem({get_delete_url}); - " - class="oh-dropdown__link oh-dropdown__link--danger" - """, - }, - ] - - details = { - "image_src": "employee_id__get_avatar", - "title": "{employee_id}", - "subtitle": " {date}
Project : {project_id}
{task_id} | Time Spent : {time_spent}", - } - - card_status_class = "status-{status}" - - card_status_indications = [ - ( - "in-progress--dot", - _("In progress"), - """ - onclick=" - $('#applyFilter').closest('form').find('[name=status]').val('in_Progress'); - $('#applyFilter').click(); - - " - """, - ), - ( - "completed--dot", - _("Completed"), - """ - onclick=" - $('#applyFilter').closest('form').find('[name=status]').val('completed'); - $('#applyFilter').click(); - - " - """, - ), - ] - - card_attrs = """ - hx-get='{detail_view}?instance_ids={ordered_ids}' - hx-target="#genericModalBody" - data-target="#genericModal" - data-toggle="oh-modal-toggle" - """ - - -@method_decorator(login_required, name="dispatch") -@method_decorator( - is_projectmanager_or_member_or_perms("project.view_timesheet"), name="dispatch" -) -class TimeSheetDetailView(HorillaDetailedView): - """ - detail view of the page - """ - - model = TimeSheet - title = _("Details") - header = { - "title": "employee_id", - "subtitle": "project_id", - "avatar": "employee_id__get_avatar", - } - - body = [ - (_("Task"), "task_id"), - (_("Date"), "date"), - (_("Time Spent"), "time_spent"), - (_("Status"), "status_column"), - (_("Description"), "description"), - ] - - action_method = "detail_actions" +""" +CBV of time sheet page +""" + +from typing import Any + +from django import forms +from django.contrib import messages +from django.db.models import Q +from django.http import HttpResponse +from django.shortcuts import render +from django.urls import resolve, reverse +from django.utils.decorators import method_decorator +from django.utils.translation import gettext_lazy as _ + +from employee.models import Employee +from horilla_views.cbv_methods import login_required +from horilla_views.generic.cbv.views import ( + HorillaCardView, + HorillaDetailedView, + HorillaFormView, + HorillaListView, + HorillaNavView, + TemplateView, +) +from project.cbv.cbv_decorators import is_projectmanager_or_member_or_perms +from project.cbv.projects import DynamicProjectCreationFormView +from project.cbv.tasks import DynamicTaskCreateFormView +from project.filters import TimeSheetFilter +from project.forms import TimeSheetForm +from project.models import Project, Task, TimeSheet + + +@method_decorator(login_required, name="dispatch") +@method_decorator( + is_projectmanager_or_member_or_perms("project.view_timesheet"), name="dispatch" +) +class TimeSheetView(TemplateView): + """ + for time sheet page + """ + + template_name = "cbv/timesheet/timesheet.html" + + +@method_decorator(login_required, name="dispatch") +@method_decorator( + is_projectmanager_or_member_or_perms("project.view_timesheet"), name="dispatch" +) +class TimeSheetNavView(HorillaNavView): + """ + Nav bar + """ + + template_name = "cbv/timesheet/timesheet_nav.html" + + def __init__(self, **kwargs: Any) -> None: + super().__init__(**kwargs) + self.search_url = reverse("time-sheet-list") + url = f"{reverse('personal-time-sheet-view',kwargs={'emp_id': self.request.user.employee_get.id})}" + self.actions = [ + { + "action": _("Delete"), + "attrs": """ + class="oh-dropdown__link--danger" + data-action ="delete" + onclick="deleteTimeSheet();" + style="cursor: pointer; color:red !important" + """, + }, + ] + self.view_types = [ + { + "type": "list", + "icon": "list-outline", + "url": reverse("time-sheet-list"), + "attrs": """ + title ='List' + """, + }, + { + "type": "card", + "icon": "grid-outline", + "url": reverse("time-sheet-card"), + "attrs": """ + title ='Card' + """, + }, + { + "type": "graph", + "icon": "bar-chart", + "attrs": f""" + onclick="event.stopPropagation(); + window.location.href='{url}'" + title ='Graph' + """, + }, + ] + + self.create_attrs = f""" + onclick = "event.stopPropagation();" + data-toggle="oh-modal-toggle" + data-target="#genericModal" + hx-target="#genericModalBody" + hx-get="{reverse('create-time-sheet')}" + """ + + group_by_fields = [ + ("employee_id", _("Employee")), + ("project_id", _("Project")), + ("date", _("Date")), + ("status", _("Status")), + ( + "employee_id__employee_work_info__reporting_manager_id", + _("Reporting Manager"), + ), + ("employee_id__employee_work_info__department_id", _("Department")), + ("employee_id__employee_work_info__job_position_id", _("Job Position")), + ("employee_id__employee_work_info__employee_type_id", _("Employement Type")), + ("employee_id__employee_work_info__company_id", _("Company")), + ] + + nav_title = _("Time Sheet") + filter_instance = TimeSheetFilter() + filter_form_context_name = "form" + filter_body_template = "cbv/timesheet/filter.html" + search_swap_target = "#listContainer" + + +@method_decorator(login_required, name="dispatch") +@method_decorator( + is_projectmanager_or_member_or_perms("project.view_timesheet"), name="dispatch" +) +class TimeSheetList(HorillaListView): + """ + Time sheet list view + """ + + def get_queryset(self): + queryset = super().get_queryset() + if not self.request.user.has_perm("project.view_timesheet"): + employee = self.request.user.employee_get + queryset = queryset.filter( + Q(task_id__task_managers=employee) + | Q(project_id__managers=employee) + | Q(employee_id=employee) + ).distinct() + return queryset + + def __init__(self, **kwargs: Any) -> None: + super().__init__(**kwargs) + + self.search_url = reverse("time-sheet-list") + self.action_method = "actions" + + model = TimeSheet + filter_class = TimeSheetFilter + + columns = [ + (_("Employee"), "employee_id", "employee_id__get_avatar"), + (_("Project"), "project_id"), + (_("Task"), "task_id"), + (_("Date"), "date"), + (_("Time Spent"), "time_spent"), + (_("Status"), "status_column"), + (_("Description"), "description"), + ] + + sortby_mapping = [ + ("Employee", "employee_id__employee_first_name", "employee_id__get_avatar"), + ("Project", "project_id__title"), + ("Task", "task_id__title"), + ("Time Spent", "time_spent"), + ("Date", "date"), + ] + + row_status_indications = [ + ( + "in-progress--dot", + _("In progress"), + """ + onclick=" + $('#applyFilter').closest('form').find('[name=status]').val('in_Progress'); + $('#applyFilter').click(); + + " + """, + ), + ( + "completed--dot", + _("Completed"), + """ + onclick=" + $('#applyFilter').closest('form').find('[name=status]').val('completed'); + $('#applyFilter').click(); + + " + """, + ), + ] + row_attrs = """ + hx-get='{detail_view}?instance_ids={ordered_ids}' + hx-target="#genericModalBody" + data-target="#genericModal" + data-toggle="oh-modal-toggle" + """ + + row_status_class = "status-{status}" + + +@method_decorator(login_required, name="dispatch") +@method_decorator( + is_projectmanager_or_member_or_perms("project.view_timesheet"), name="dispatch" +) +class TaskTimeSheet(TimeSheetList): + + row_attrs = "" + row_status_indications = False + bulk_select_option = False + + def __init__(self, **kwargs: Any) -> None: + super().__init__(**kwargs) + self.view_id = "task-timesheet-container" + task_id = resolve(self.request.path_info).kwargs.get("task_id") + self.request.task_id = task_id + employee_id = self.request.GET.get("employee_id") + if employee_id: + self.action_method = "actions" + + def get_context_data(self, **kwargs: Any): + context = super().get_context_data(**kwargs) + task_id = self.kwargs.get("task_id") + task = Task.objects.get(id=task_id) + project = task.project + context["task_id"] = task_id + context["project"] = project + context["task"] = task + return context + + template_name = "cbv/timesheet/task_timesheet.html" + + def get_queryset(self): + queryset = HorillaListView.get_queryset(self) + task_id = self.kwargs.get("task_id") + task = Task.objects.filter(id=task_id).first() + queryset = TimeSheet.objects.filter(task_id=task_id) + queryset = queryset.filter(task_id=task_id) + employee_id = self.request.GET.get("employee_id") + if employee_id: + employee = Employee.objects.filter(id=employee_id).first() + if ( + not employee in task.task_managers.all() + and not employee in task.project.managers.all() + and not employee.employee_user_id.is_superuser + ): + queryset = queryset.filter(employee_id=employee_id) + + return queryset + + +@method_decorator(login_required, name="dispatch") +@method_decorator( + is_projectmanager_or_member_or_perms("project.view_timesheet"), name="dispatch" +) +class TimeSheetFormView(HorillaFormView): + """ + form view for create project + """ + + def __init__(self, **kwargs: Any) -> None: + super().__init__(**kwargs) + self.dynamic_create_fields = [ + ("task_id", DynamicTaskCreateFormView), + ] + if self.request.user.has_perm("project.add_project"): + self.dynamic_create_fields.append( + ("project_id", DynamicProjectCreationFormView) + ) + + form_class = TimeSheetForm + model = TimeSheet + new_display_title = _("Create Time Sheet") + # template_name = "cbv/timesheet/form.html" + + def get_initial(self) -> dict: + initial = super().get_initial() + task_id = self.kwargs.get("task_id") + if task_id: + task = Task.objects.get(id=task_id) + project_id = task.project + initial["project_id"] = project_id.id + initial["task_id"] = task.id + return initial + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + task_id = self.kwargs.get("task_id") + user_employee_id = self.request.user.employee_get.id + project = None + if task_id: + task = Task.objects.get(id=task_id) + project = task.project + employee = Employee.objects.filter(id=user_employee_id) + + if self.form.instance.pk: + task_id = self.form.instance.task_id.id + project = self.form.instance.project_id + tasks = Task.objects.filter(project=project) + employee = Employee.objects.filter(id=user_employee_id) + task = Task.objects.get(id=task_id) + self.form.fields["task_id"].queryset = tasks + self.form.fields["task_id"].choices = [ + (item.id, item.title) for item in tasks + ] + self.form.fields["task_id"].choices.append( + ("dynamic_create", "Dynamic create") + ) + task_id = self.request.GET.get("task_id") + self.form_class.verbose_name = _("Update Time Sheet") + # If the timesheet create from task or project + if project: + if self.request.user.is_superuser or self.request.user.has_perm( + "project.add_project" + ): + members = ( + project.managers.all() + | project.members.all() + | task.task_members.all() + | task.task_managers.all() + ).distinct() + elif employee.first() in project.managers.all(): + members = ( + employee + | project.members.all() + | task.task_members.all() + | task.task_managers.all() + ).distinct() + elif employee.first() in task.task_managers.all(): + members = (employee | task.task_members.all()).distinct() + else: + members = employee + if task_id: + self.form.fields["project_id"].widget = forms.HiddenInput() + self.form.fields["task_id"].widget = forms.HiddenInput() + self.form.fields["employee_id"].queryset = members + + # If the timesheet create directly + else: + employee = self.request.user.employee_get + if self.request.user.has_perm("project.add_timesheet"): + projects = Project.objects.all() + else: + projects = ( + Project.objects.filter(managers=employee) + | Project.objects.filter(members=employee) + | Project.objects.filter( + id__in=Task.objects.filter(task_managers=employee).values_list( + "project", flat=True + ) + ) + | Project.objects.filter( + id__in=Task.objects.filter(task_members=employee).values_list( + "project", flat=True + ) + ) + ).distinct() + self.form.fields["project_id"].queryset = projects + return context + + def form_valid(self, form: TimeSheetForm) -> HttpResponse: + if form.is_valid(): + if form.instance.pk: + message = _(f"{self.form.instance} Updated") + else: + message = _("New time sheet created") + form.save() + messages.success(self.request, _(message)) + return self.HttpResponse() + return super().form_valid(form) + + +@method_decorator(login_required, name="dispatch") +@method_decorator( + is_projectmanager_or_member_or_perms("project.view_timesheet"), name="dispatch" +) +class TimeSheetCardView(HorillaCardView): + """ + For card view + """ + + model = TimeSheet + filter_class = TimeSheetFilter + + def get_queryset(self): + queryset = super().get_queryset() + if not self.request.user.has_perm("project.view_timesheet"): + employee = self.request.user.employee_get + queryset = queryset.filter( + Q(task_id__task_managers=employee) + | Q(project_id__managers=employee) + | Q(employee_id=employee) + ).distinct() + return queryset + + def __init__(self, **kwargs: Any) -> None: + super().__init__(**kwargs) + self.search_url = reverse("time-sheet-card") + self.actions = [ + { + "action": "Edit", + "attrs": """ + hx-get='{get_update_url}' + hx-target='#genericModalBody' + data-toggle="oh-modal-toggle" + data-target="#genericModal" + class="oh-dropdown__link" + """, + }, + { + "action": "Delete", + "attrs": """ + onclick=" + event.stopPropagation() + deleteItem({get_delete_url}); + " + class="oh-dropdown__link oh-dropdown__link--danger" + """, + }, + ] + + details = { + "image_src": "employee_id__get_avatar", + "title": "{employee_id}", + "subtitle": " {date}
Project : {project_id}
{task_id} | Time Spent : {time_spent}", + } + + card_status_class = "status-{status}" + + card_status_indications = [ + ( + "in-progress--dot", + _("In progress"), + """ + onclick=" + $('#applyFilter').closest('form').find('[name=status]').val('in_Progress'); + $('#applyFilter').click(); + + " + """, + ), + ( + "completed--dot", + _("Completed"), + """ + onclick=" + $('#applyFilter').closest('form').find('[name=status]').val('completed'); + $('#applyFilter').click(); + + " + """, + ), + ] + + card_attrs = """ + hx-get='{detail_view}?instance_ids={ordered_ids}' + hx-target="#genericModalBody" + data-target="#genericModal" + data-toggle="oh-modal-toggle" + """ + + +@method_decorator(login_required, name="dispatch") +@method_decorator( + is_projectmanager_or_member_or_perms("project.view_timesheet"), name="dispatch" +) +class TimeSheetDetailView(HorillaDetailedView): + """ + detail view of the page + """ + + model = TimeSheet + title = _("Details") + header = { + "title": "employee_id", + "subtitle": "project_id", + "avatar": "employee_id__get_avatar", + } + + body = [ + (_("Task"), "task_id"), + (_("Date"), "date"), + (_("Time Spent"), "time_spent"), + (_("Status"), "status_column"), + (_("Description"), "description"), + ] + + action_method = "detail_actions" diff --git a/project/decorator.py b/project/decorator.py index 06622fb82..88a596157 100644 --- a/project/decorator.py +++ b/project/decorator.py @@ -1,189 +1,189 @@ -from django.contrib import messages -from django.http import HttpResponse - -from project.methods import ( - any_project_manager, - any_project_member, - any_task_manager, - any_task_member, -) - -from .models import Project, ProjectStage, Task - -decorator_with_arguments = ( - lambda decorator: lambda *args, **kwargs: lambda func: decorator( - func, *args, **kwargs - ) -) - - -@decorator_with_arguments -def is_projectmanager_or_member_or_perms(function, perm): - def _function(request, *args, **kwargs): - """ - This method is used to check the employee is project manager or not - """ - user = request.user - if ( - user.has_perm(perm) - or any_project_manager(user) - or any_project_member(user) - or any_task_manager(user) - or any_task_member(user) - ): - return function(request, *args, **kwargs) - messages.info(request, "You don't have permission.") - return HttpResponse("") - - return _function - - -@decorator_with_arguments -def project_update_permission(function=None, *args, **kwargs): - def check_project_member( - request, - project_id=None, - *args, - **kwargs, - ): - """ - This method is used to check the employee is project member or not - """ - project = Project.objects.get(id=project_id) - employee = request.user.employee_get - if ( - request.user.has_perm("project.change_project") - or employee in project.managers.all() - or employee in project.members.all() - or any( - employee in task.task_managers.all() for task in project.task_set.all() - ) - or any( - employee in task.task_members.all() for task in project.task_set.all() - ) - ): - return function(request, *args, project_id=project_id, **kwargs) - messages.info(request, "You dont have permission.") - return HttpResponse("") - # return function(request, *args, **kwargs) - - return check_project_member - - -@decorator_with_arguments -def project_delete_permission(function=None, *args, **kwargs): - def is_project_manager( - request, - project_id=None, - *args, - **kwargs, - ): - """ - This method is used to check the employee is project manager or not - """ - project = Project.objects.get(id=project_id) - if ( - request.user.employee_get in project.managers.all() - or request.user.is_superuser - ): - return function(request, *args, project_id=project_id, **kwargs) - messages.info(request, "You dont have permission.") - return HttpResponse("") - - return is_project_manager - - -@decorator_with_arguments -def project_stage_update_permission(function=None, *args, **kwargs): - def check_project_member( - request, - stage_id=None, - *args, - **kwargs, - ): - """ - This method is used to check the employee is project stage member or not - """ - project = ProjectStage.objects.get(id=stage_id).project - if ( - request.user.has_perm("project.change_project") - or request.user.has_perm("project.change_task") - or request.user.employee_get in project.managers.all() - or request.user.employee_get in project.members.all() - ): - return function(request, *args, stage_id=stage_id, **kwargs) - messages.info(request, "You dont have permission.") - return HttpResponse("") - # return function(request, *args, **kwargs) - - return check_project_member - - -@decorator_with_arguments -def project_stage_delete_permission(function=None, *args, **kwargs): - def is_project_manager( - request, - stage_id=None, - *args, - **kwargs, - ): - """ - This method is used to check the employee is project stage manager or not - """ - project = ProjectStage.objects.get(id=stage_id).project - if ( - request.user.employee_get in project.managers.all() - or request.user.is_superuser - ): - return function(request, *args, stage_id=stage_id, **kwargs) - messages.info(request, "You dont have permission.") - return HttpResponse("") - - return is_project_manager - - -@decorator_with_arguments -def task_update_permission(function=None, *args, **kwargs): - def is_task_member(request, task_id): - """ - This method is used to check the employee is task member or not - """ - task = Task.objects.get(id=task_id) - project = task.project - - if ( - request.user.has_perm("project.change_task") - or request.user.has_perm("project.change_project") - or request.user.employee_get in task.task_managers.all() - or request.user.employee_get in task.task_members.all() - or request.user.employee_get in project.managers.all() - or request.user.employee_get in project.members.all() - ): - return function(request, *args, task_id=task_id, **kwargs) - - messages.info(request, "You dont have permission.") - return HttpResponse("") - - return is_task_member - - -@decorator_with_arguments -def task_delete_permission(function=None, *args, **kwargs): - def is_task_manager(request, task_id): - """ - This method is used to check the employee is task manager or not - """ - task = Task.objects.get(id=task_id) - project = task.project - - if ( - request.user.is_superuser - or request.user.employee_get in task.task_managers.all() - or request.user.employee_get in project.managers.all() - ): - return function(request, task_id=task_id) - - messages.info(request, "You dont have permission.") - return HttpResponse("") - - return is_task_manager +from django.contrib import messages +from django.http import HttpResponse + +from project.methods import ( + any_project_manager, + any_project_member, + any_task_manager, + any_task_member, +) + +from .models import Project, ProjectStage, Task + +decorator_with_arguments = ( + lambda decorator: lambda *args, **kwargs: lambda func: decorator( + func, *args, **kwargs + ) +) + + +@decorator_with_arguments +def is_projectmanager_or_member_or_perms(function, perm): + def _function(request, *args, **kwargs): + """ + This method is used to check the employee is project manager or not + """ + user = request.user + if ( + user.has_perm(perm) + or any_project_manager(user) + or any_project_member(user) + or any_task_manager(user) + or any_task_member(user) + ): + return function(request, *args, **kwargs) + messages.info(request, "You don't have permission.") + return HttpResponse("") + + return _function + + +@decorator_with_arguments +def project_update_permission(function=None, *args, **kwargs): + def check_project_member( + request, + project_id=None, + *args, + **kwargs, + ): + """ + This method is used to check the employee is project member or not + """ + project = Project.objects.get(id=project_id) + employee = request.user.employee_get + if ( + request.user.has_perm("project.change_project") + or employee in project.managers.all() + or employee in project.members.all() + or any( + employee in task.task_managers.all() for task in project.task_set.all() + ) + or any( + employee in task.task_members.all() for task in project.task_set.all() + ) + ): + return function(request, *args, project_id=project_id, **kwargs) + messages.info(request, "You dont have permission.") + return HttpResponse("") + # return function(request, *args, **kwargs) + + return check_project_member + + +@decorator_with_arguments +def project_delete_permission(function=None, *args, **kwargs): + def is_project_manager( + request, + project_id=None, + *args, + **kwargs, + ): + """ + This method is used to check the employee is project manager or not + """ + project = Project.objects.get(id=project_id) + if ( + request.user.employee_get in project.managers.all() + or request.user.is_superuser + ): + return function(request, *args, project_id=project_id, **kwargs) + messages.info(request, "You dont have permission.") + return HttpResponse("") + + return is_project_manager + + +@decorator_with_arguments +def project_stage_update_permission(function=None, *args, **kwargs): + def check_project_member( + request, + stage_id=None, + *args, + **kwargs, + ): + """ + This method is used to check the employee is project stage member or not + """ + project = ProjectStage.objects.get(id=stage_id).project + if ( + request.user.has_perm("project.change_project") + or request.user.has_perm("project.change_task") + or request.user.employee_get in project.managers.all() + or request.user.employee_get in project.members.all() + ): + return function(request, *args, stage_id=stage_id, **kwargs) + messages.info(request, "You dont have permission.") + return HttpResponse("") + # return function(request, *args, **kwargs) + + return check_project_member + + +@decorator_with_arguments +def project_stage_delete_permission(function=None, *args, **kwargs): + def is_project_manager( + request, + stage_id=None, + *args, + **kwargs, + ): + """ + This method is used to check the employee is project stage manager or not + """ + project = ProjectStage.objects.get(id=stage_id).project + if ( + request.user.employee_get in project.managers.all() + or request.user.is_superuser + ): + return function(request, *args, stage_id=stage_id, **kwargs) + messages.info(request, "You dont have permission.") + return HttpResponse("") + + return is_project_manager + + +@decorator_with_arguments +def task_update_permission(function=None, *args, **kwargs): + def is_task_member(request, task_id): + """ + This method is used to check the employee is task member or not + """ + task = Task.objects.get(id=task_id) + project = task.project + + if ( + request.user.has_perm("project.change_task") + or request.user.has_perm("project.change_project") + or request.user.employee_get in task.task_managers.all() + or request.user.employee_get in task.task_members.all() + or request.user.employee_get in project.managers.all() + or request.user.employee_get in project.members.all() + ): + return function(request, *args, task_id=task_id, **kwargs) + + messages.info(request, "You dont have permission.") + return HttpResponse("") + + return is_task_member + + +@decorator_with_arguments +def task_delete_permission(function=None, *args, **kwargs): + def is_task_manager(request, task_id): + """ + This method is used to check the employee is task manager or not + """ + task = Task.objects.get(id=task_id) + project = task.project + + if ( + request.user.is_superuser + or request.user.employee_get in task.task_managers.all() + or request.user.employee_get in project.managers.all() + ): + return function(request, task_id=task_id) + + messages.info(request, "You dont have permission.") + return HttpResponse("") + + return is_task_manager diff --git a/project/methods.py b/project/methods.py index 0b3bf186c..ba093a952 100644 --- a/project/methods.py +++ b/project/methods.py @@ -1,239 +1,239 @@ -import random - -from django.contrib import messages -from django.core.paginator import Paginator -from django.http import HttpResponse, HttpResponseRedirect -from django.shortcuts import render - -from base.methods import get_pagination, get_subordinates -from employee.models import Employee -from project.models import Project, Task, TimeSheet - -decorator_with_arguments = ( - lambda decorator: lambda *args, **kwargs: lambda func: decorator( - func, *args, **kwargs - ) -) - - -def strtime_seconds(time): - """ - this method is used to reconvert time in H:M formate string back to seconds and return it - args: - time : time in H:M format - """ - ftr = [3600, 60, 1] - return sum(a * b for a, b in zip(ftr, map(int, time.split(":")))) - - -def paginator_qry(qryset, page_number): - """ - This method is used to generate common paginator limit. - """ - paginator = Paginator(qryset, get_pagination()) - qryset = paginator.get_page(page_number) - return qryset - - -def random_color_generator(): - r = random.randint(0, 255) - g = random.randint(0, 255) - b = random.randint(0, 255) - if r == g or g == b or b == r: - random_color_generator() - return f"rgba({r}, {g}, {b} , 0.7)" - - -# color_palette=[] -# Function to generate distinct colors for each project -def generate_colors(num_colors): - # Define a color palette with distinct colors - color_palette = [ - "rgba(255, 99, 132, 1)", # Red - "rgba(54, 162, 235, 1)", # Blue - "rgba(255, 206, 86, 1)", # Yellow - "rgba(75, 192, 192, 1)", # Green - "rgba(153, 102, 255, 1)", # Purple - "rgba(255, 159, 64, 1)", # Orange - ] - - if num_colors > len(color_palette): - for i in range(num_colors - len(color_palette)): - color_palette.append(random_color_generator()) - - colors = [] - for i in range(num_colors): - # color=random_color_generator() - colors.append(color_palette[i % len(color_palette)]) - - return colors - - -def any_project_manager(user): - employee = user.employee_get - if employee.project_managers.all().exists(): - return True - else: - return False - - -def any_project_member(user): - employee = user.employee_get - if employee.project_members.all().exists(): - return True - else: - return False - - -def any_task_manager(user): - employee = user.employee_get - if employee.task_set.all().exists(): - return True - else: - return False - - -def any_task_member(user): - employee = user.employee_get - if employee.tasks.all().exists(): - return True - else: - return False - - -@decorator_with_arguments -def is_projectmanager_or_member_or_perms(function, perm): - def _function(request, *args, **kwargs): - """ - This method is used to check the employee is project manager or not - """ - user = request.user - if ( - user.has_perm(perm) - or any_project_manager(user) - or any_project_member(user) - or any_task_manager(user) - or any_task_member(user) - ): - return function(request, *args, **kwargs) - messages.info(request, "You don't have permission.") - return HttpResponseRedirect(request.META.get("HTTP_REFERER", "/")) - - return _function - - -def is_task_member(request, task_id): - """ - This method is used to check the employee is task member or not - """ - if ( - request.user.has_perm("project.change_task") - or request.user.employee_get in Task.objects.get(id=task_id).task_managers.all() - or request.user.employee_get in Task.objects.get(id=task_id).task_members.all() - ): - return True - return False - - -def is_task_manager(request, task_id): - """ - This method is used to check the employee is task member or not - """ - if ( - request.user.has_perm("project.delete_task") - or request.user.employee_get in Task.objects.get(id=task_id).task_managers.all() - ): - return True - return False - - -def time_sheet_update_permissions(request, time_sheet_id): - if ( - request.user.has_perm("project.change_timesheet") - or request.user.employee_get - == TimeSheet.objects.get(id=time_sheet_id).employee_id - or TimeSheet.objects.get(id=time_sheet_id).employee_id - in Employee.objects.filter( - employee_work_info__reporting_manager_id=request.user.employee_get - ) - ): - return True - else: - return False - - -def time_sheet_delete_permissions(request, time_sheet_id): - employee = request.user.employee_get - timesheet = TimeSheet.objects.filter(id=time_sheet_id).first() - if ( - request.user.has_perm("project.delete_timesheet") - or timesheet.employee_id == employee - or employee in timesheet.task_id.task_managers.all() - or employee in timesheet.task_id.project.managers.all() - ): - return True - else: - return False - - -def get_all_project_members_and_managers(): - all_projects = Project.objects.all() - all_tasks = Task.objects.all() - - all_ids = set() - - for project in all_projects: - all_ids.update( - manager.id for manager in project.managers.all() - ) # Add manager ID - all_ids.update(member.id for member in project.members.all()) # Add member IDs - - for task in all_tasks: - all_ids.update( - task_manager.id for task_manager in task.task_managers.all() - ) # Add task manager ID - all_ids.update( - task_member.id for task_member in task.task_members.all() - ) # Add task member IDs - - # Return a single queryset for all employees - return Employee.objects.filter(id__in=all_ids) - - -def has_subordinates(request): - """ - used to check whether the project contain users subordinates or not - """ - all_members_info = get_all_project_members_and_managers() - subordinates = get_subordinates(request) - - member = {member for member in all_members_info} - - for subordinate in subordinates: - if subordinate in member: - return True - - return False - - -def is_project_manager_or_super_user(request, project): - """ - Method to check whether user is a manager of project or - user is a super user. - """ - return ( - request.user.employee_get in project.managers.all() or request.user.is_superuser - ) - - -def you_dont_have_permission(request): - """ - Method to return you dont have permission - """ - messages.info(request, "You dont have permission.") - previous_url = request.META.get("HTTP_REFERER", "/") - key = "HTTP_HX_REQUEST" - if key in request.META.keys(): - return render(request, "decorator_404.html") - script = f'' - return HttpResponse(script) +import random + +from django.contrib import messages +from django.core.paginator import Paginator +from django.http import HttpResponse, HttpResponseRedirect +from django.shortcuts import render + +from base.methods import get_pagination, get_subordinates +from employee.models import Employee +from project.models import Project, Task, TimeSheet + +decorator_with_arguments = ( + lambda decorator: lambda *args, **kwargs: lambda func: decorator( + func, *args, **kwargs + ) +) + + +def strtime_seconds(time): + """ + this method is used to reconvert time in H:M formate string back to seconds and return it + args: + time : time in H:M format + """ + ftr = [3600, 60, 1] + return sum(a * b for a, b in zip(ftr, map(int, time.split(":")))) + + +def paginator_qry(qryset, page_number): + """ + This method is used to generate common paginator limit. + """ + paginator = Paginator(qryset, get_pagination()) + qryset = paginator.get_page(page_number) + return qryset + + +def random_color_generator(): + r = random.randint(0, 255) + g = random.randint(0, 255) + b = random.randint(0, 255) + if r == g or g == b or b == r: + random_color_generator() + return f"rgba({r}, {g}, {b} , 0.7)" + + +# color_palette=[] +# Function to generate distinct colors for each project +def generate_colors(num_colors): + # Define a color palette with distinct colors + color_palette = [ + "rgba(255, 99, 132, 1)", # Red + "rgba(54, 162, 235, 1)", # Blue + "rgba(255, 206, 86, 1)", # Yellow + "rgba(75, 192, 192, 1)", # Green + "rgba(153, 102, 255, 1)", # Purple + "rgba(255, 159, 64, 1)", # Orange + ] + + if num_colors > len(color_palette): + for i in range(num_colors - len(color_palette)): + color_palette.append(random_color_generator()) + + colors = [] + for i in range(num_colors): + # color=random_color_generator() + colors.append(color_palette[i % len(color_palette)]) + + return colors + + +def any_project_manager(user): + employee = user.employee_get + if employee.project_managers.all().exists(): + return True + else: + return False + + +def any_project_member(user): + employee = user.employee_get + if employee.project_members.all().exists(): + return True + else: + return False + + +def any_task_manager(user): + employee = user.employee_get + if employee.task_set.all().exists(): + return True + else: + return False + + +def any_task_member(user): + employee = user.employee_get + if employee.tasks.all().exists(): + return True + else: + return False + + +@decorator_with_arguments +def is_projectmanager_or_member_or_perms(function, perm): + def _function(request, *args, **kwargs): + """ + This method is used to check the employee is project manager or not + """ + user = request.user + if ( + user.has_perm(perm) + or any_project_manager(user) + or any_project_member(user) + or any_task_manager(user) + or any_task_member(user) + ): + return function(request, *args, **kwargs) + messages.info(request, "You don't have permission.") + return HttpResponseRedirect(request.META.get("HTTP_REFERER", "/")) + + return _function + + +def is_task_member(request, task_id): + """ + This method is used to check the employee is task member or not + """ + if ( + request.user.has_perm("project.change_task") + or request.user.employee_get in Task.objects.get(id=task_id).task_managers.all() + or request.user.employee_get in Task.objects.get(id=task_id).task_members.all() + ): + return True + return False + + +def is_task_manager(request, task_id): + """ + This method is used to check the employee is task member or not + """ + if ( + request.user.has_perm("project.delete_task") + or request.user.employee_get in Task.objects.get(id=task_id).task_managers.all() + ): + return True + return False + + +def time_sheet_update_permissions(request, time_sheet_id): + if ( + request.user.has_perm("project.change_timesheet") + or request.user.employee_get + == TimeSheet.objects.get(id=time_sheet_id).employee_id + or TimeSheet.objects.get(id=time_sheet_id).employee_id + in Employee.objects.filter( + employee_work_info__reporting_manager_id=request.user.employee_get + ) + ): + return True + else: + return False + + +def time_sheet_delete_permissions(request, time_sheet_id): + employee = request.user.employee_get + timesheet = TimeSheet.objects.filter(id=time_sheet_id).first() + if ( + request.user.has_perm("project.delete_timesheet") + or timesheet.employee_id == employee + or employee in timesheet.task_id.task_managers.all() + or employee in timesheet.task_id.project.managers.all() + ): + return True + else: + return False + + +def get_all_project_members_and_managers(): + all_projects = Project.objects.all() + all_tasks = Task.objects.all() + + all_ids = set() + + for project in all_projects: + all_ids.update( + manager.id for manager in project.managers.all() + ) # Add manager ID + all_ids.update(member.id for member in project.members.all()) # Add member IDs + + for task in all_tasks: + all_ids.update( + task_manager.id for task_manager in task.task_managers.all() + ) # Add task manager ID + all_ids.update( + task_member.id for task_member in task.task_members.all() + ) # Add task member IDs + + # Return a single queryset for all employees + return Employee.objects.filter(id__in=all_ids) + + +def has_subordinates(request): + """ + used to check whether the project contain users subordinates or not + """ + all_members_info = get_all_project_members_and_managers() + subordinates = get_subordinates(request) + + member = {member for member in all_members_info} + + for subordinate in subordinates: + if subordinate in member: + return True + + return False + + +def is_project_manager_or_super_user(request, project): + """ + Method to check whether user is a manager of project or + user is a super user. + """ + return ( + request.user.employee_get in project.managers.all() or request.user.is_superuser + ) + + +def you_dont_have_permission(request): + """ + Method to return you dont have permission + """ + messages.info(request, "You dont have permission.") + previous_url = request.META.get("HTTP_REFERER", "/") + key = "HTTP_HX_REQUEST" + if key in request.META.keys(): + return render(request, "decorator_404.html") + script = f'' + return HttpResponse(script) diff --git a/project/models.py b/project/models.py index a148e750b..6893fcf94 100644 --- a/project/models.py +++ b/project/models.py @@ -1,617 +1,617 @@ -""" -models.py - -This module is used to register models for project app - -""" - -import datetime -from datetime import date - -from django.apps import apps -from django.core.exceptions import ValidationError -from django.db import models -from django.templatetags.static import static -from django.urls import reverse, reverse_lazy -from django.utils import timezone -from django.utils.html import format_html -from django.utils.translation import gettext_lazy as _ - -from employee.models import Employee -from horilla.horilla_middlewares import _thread_locals -from horilla_views.cbv_methods import render_template - -# Create your models here. - - -def validate_time_format(value): - """ - this method is used to validate the format of duration like fields. - """ - if len(value) > 5: - raise ValidationError(_("Invalid format, it should be HH:MM format")) - try: - hour, minute = value.split(":") - - if len(hour) < 2 or len(minute) < 2: - raise ValidationError(_("Invalid format, it should be HH:MM format")) - - minute = int(minute) - if len(hour) > 2 or minute not in range(60): - raise ValidationError(_("Invalid time")) - except ValueError as error: - raise ValidationError(_("Invalid format")) from error - - -class Project(models.Model): - PROJECT_STATUS = [ - ("new", "New"), - ("in_progress", "In Progress"), - ("completed", "Completed"), - ("on_hold", "On Hold"), - ("cancelled", "Cancelled"), - ("expired", "Expired"), - ] - title = models.CharField(max_length=200, unique=True, verbose_name="Name") - managers = models.ManyToManyField( - Employee, - blank=True, - related_name="project_managers", - verbose_name="Project Managers", - ) - members = models.ManyToManyField( - Employee, - blank=True, - related_name="project_members", - verbose_name="Project Members", - ) - status = models.CharField(choices=PROJECT_STATUS, max_length=250, default="new") - start_date = models.DateField() - end_date = models.DateField(null=True, blank=True) - document = models.FileField( - upload_to="project/files", blank=True, null=True, verbose_name="Project File" - ) - is_active = models.BooleanField(default=True) - description = models.TextField() - objects = models.Manager() - - def get_description(self, length=50): - """ - Returns a truncated version of the description attribute. - - Parameters: - length (int): The maximum length of the returned description. - """ - return ( - self.description - if len(self.description) <= length - else self.description[:length] + "..." - ) - - def get_managers(self): - """ - managers column - """ - employees = self.managers.all() - if employees: - employee_names_string = "
".join( - [str(employee) for employee in employees] - ) - return employee_names_string - - def get_members(self): - """ - members column - """ - employees = self.members.all() - if employees: - employee_names_string = "
".join( - [str(employee) for employee in employees] - ) - return employee_names_string - - def get_avatar(self): - """ - Method will retun the api to the avatar or path to the profile image - """ - url = f"https://ui-avatars.com/api/?name={self.title}&background=random" - return url - - def get_document_html(self): - if self.document: - document_url = self.document.url - image_url = static("images/ui/project/document.png") - return format_html( - '' - '' - "  View" - "", - document_url, - image_url, - ) - - def redirect(self): - """ - This method generates an onclick URL for task viewing. - """ - request = getattr(_thread_locals, "request", None) - employee = request.user.employee_get - url = reverse_lazy("task-view", kwargs={"project_id": self.pk}) - - if ( - employee in self.managers.all() - or employee in self.members.all() - or any(employee in task.task_managers.all() for task in self.task_set.all()) - or any(employee in task.task_members.all() for task in self.task_set.all()) - or request.user.has_perm("project.view_project") - ): - return f"onclick=\"window.location.href='{url}?view=list'\"" - return "" - - def get_detail_url(self): - """ - This method to get detail url - """ - url = reverse_lazy("project-detailed-view", kwargs={"pk": self.pk}) - return url - - def get_update_url(self): - """ - This method to get update url - """ - url = reverse_lazy("update-project", kwargs={"pk": self.pk}) - return url - - def get_archive_url(self): - """ - This method to get archive url - """ - url = reverse_lazy("project-archive", kwargs={"project_id": self.pk}) - return url - - def get_task_badge_html(self): - task_count = self.task_set.count() - title = self.title - return format_html( - '
' - '
' - ' ' - " {1}" - " " - "
" - "
{0}
" - "
", - title, - task_count, - ) - - def get_delete_url(self): - """ - This method to get delete url - """ - url = reverse_lazy("delete-project", kwargs={"project_id": self.pk}) - message = "Are you sure you want to delete this project?" - return f"'{url}'" + "," + f"'{message}'" - - def actions(self): - """ - This method for get custom column for action. - """ - - return render_template( - path="cbv/projects/actions.html", - context={"instance": self}, - ) - - def archive_status(self): - """ - archive status - """ - if self.is_active: - return "Archive" - else: - return "Un-Archive" - - def clean(self) -> None: - # validating end date - if self.end_date is not None: - if self.end_date < self.start_date: - raise ValidationError({"document": "End date is less than start date"}) - if self.end_date < date.today(): - self.status = "expired" - - def save(self, *args, **kwargs): - is_new = self.pk is None - super().save(*args, **kwargs) - - if is_new: - ProjectStage.objects.create( - title="Todo", - project=self, - sequence=1, - is_end_stage=False, - ) - - def __str__(self): - return self.title - - def status_column(self): - return dict(self.PROJECT_STATUS).get(self.status) - - -class ProjectStage(models.Model): - """ - ProjectStage model - """ - - title = models.CharField(max_length=200) - project = models.ForeignKey( - Project, - on_delete=models.CASCADE, - null=True, - blank=True, - related_name="project_stages", - ) - sequence = models.IntegerField(null=True, blank=True, editable=False) - is_end_stage = models.BooleanField(default=False) - - def __str__(self) -> str: - return f"{self.title}" - - def clean(self) -> None: - if self.is_end_stage: - project = self.project - existing_end_stage = project.project_stages.filter( - is_end_stage=True - ).exclude(id=self.id) - - if existing_end_stage: - end_stage = project.project_stages.filter(is_end_stage=True).first() - raise ValidationError( - _(f"Already exist an end stage - {end_stage.title}.") - ) - - def save(self, *args, **kwargs): - if self.sequence is None: - last_stage = ( - ProjectStage.objects.filter(project=self.project) - .order_by("sequence") - .last() - ) - if last_stage: - self.sequence = last_stage.sequence + 1 - super().save(*args, **kwargs) - - def delete(self, *args, **kwargs): - project_stages_after = ProjectStage.objects.filter( - project=self.project, sequence__gt=self.sequence - ) - - # Decrement the sequence of the following stages - for stage in project_stages_after: - stage.sequence -= 1 - stage.save() - - super().delete(*args, **kwargs) - - class Meta: - """ - Meta class to add the additional info - """ - - unique_together = ["project", "title"] - - -class Task(models.Model): - """ - Task model - """ - - TASK_STATUS = [ - ("to_do", "To Do"), - ("in_progress", "In Progress"), - ("completed", "Completed"), - ("expired", "Expired"), - ] - title = models.CharField(max_length=200) - project = models.ForeignKey(Project, on_delete=models.CASCADE, null=True) - stage = models.ForeignKey( - ProjectStage, - on_delete=models.CASCADE, - null=True, - related_name="tasks", - verbose_name="Project Stage", - ) - task_managers = models.ManyToManyField( - Employee, - blank=True, - verbose_name="Task Managers", - ) - task_members = models.ManyToManyField( - Employee, blank=True, related_name="tasks", verbose_name="Task Members" - ) - status = models.CharField(choices=TASK_STATUS, max_length=250, default="to_do") - start_date = models.DateField(null=True, blank=True) - end_date = models.DateField(null=True, blank=True) - document = models.FileField( - upload_to="task/files", blank=True, null=True, verbose_name="Task File" - ) - is_active = models.BooleanField(default=True) - description = models.TextField() - sequence = models.IntegerField(default=0) - objects = models.Manager() - - def clean(self) -> None: - if self.end_date is not None and self.project.end_date is not None: - if ( - self.project.end_date < self.end_date - or self.project.start_date > self.end_date - ): - raise ValidationError( - { - "end_date": _( - "The task end date must be between the project's start and end dates." - ) - } - ) - if self.end_date < date.today(): - self.status = "expired" - - class Meta: - """ - Meta class to add the additional info - """ - - unique_together = ["project", "title"] - - def __str__(self): - return f"{self.title}" - - def if_project(self): - """ - Return project if have,otherwise return none - """ - - return self.project if self.project else "None" - - def task_detail_view(self): - """ - detail view of task - """ - - url = reverse("task-detail-view", kwargs={"pk": self.pk}) - return url - - def status_column(self): - """ - to get status - """ - return dict(self.TASK_STATUS).get(self.status) - - def get_managers(self): - """ - return task managers - """ - managers = self.task_managers.all() - if managers: - managers_name_string = "
".join([str(manager) for manager in managers]) - return managers_name_string - else: - return "" - - def get_members(self): - """ - return task members - """ - members = self.task_members.all() - if members: - members_name_string = "
".join([str(member) for member in members]) - return members_name_string - else: - return "" - - def actions(self): - """ - This method for get custom column for action. - """ - # request = getattr(_thread_locals, "request", None) - # is_task_manager = self.task_manager == request.user - # print(self.title) - # is_project_manager = self.project.manager == request.user if self.project else False - # print(self.project) - # has_permission = request.user.has_perm('project.view_task') # Replace 'your_app' with your app name - - # if is_task_manager or is_project_manager or has_permission: - # return render_template( - # "cbv/tasks/task_actions.html", - # {"instance": self} - # ) - # else: - # return "" - - return render_template( - path="cbv/tasks/task_actions.html", - context={"instance": self}, - ) - - def get_avatar(self): - """ - Method will retun the api to the avatar or path to the profile image - """ - url = f"https://ui-avatars.com/api/?name={self.title}&background=random" - return url - - def document_col(self): - """ - This method for get custom document coloumn . - """ - - return render_template( - path="cbv/tasks/task_document.html", - context={"instance": self}, - ) - - def detail_view_actions(self): - """ - This method for get detail view actions. - """ - - return render_template( - path="cbv/tasks/task_detail_actions.html", - context={"instance": self}, - ) - - def get_update_url(self): - """ - to get the update url - """ - url = reverse("update-task-all", kwargs={"pk": self.pk}) - return url - - def archive_status(self): - """ - archive status - """ - if self.is_active: - return "Archive" - else: - return "Un-Archive" - - def get_archive_url(self): - """ - to get archive url - """ - - url = reverse("task-all-archive", kwargs={"task_id": self.pk}) - return url - - def get_delete_url(self): - """ - to get delete url - """ - - url = reverse("delete-task", kwargs={"task_id": self.pk}) - url_with_params = f"{url}?task_all=true" - message = "Are you sure you want to delete this task?" - return f"'{url_with_params}'" + "," + f"'{message}'" - - -class TimeSheet(models.Model): - """ - TimeSheet model - """ - - TIME_SHEET_STATUS = [ - ("in_Progress", "In Progress"), - ("completed", "Completed"), - ] - project_id = models.ForeignKey( - Project, - on_delete=models.CASCADE, - null=True, - related_name="project_timesheet", - verbose_name="Project", - ) - task_id = models.ForeignKey( - Task, - on_delete=models.CASCADE, - null=True, - related_name="task_timesheet", - verbose_name="Task", - ) - employee_id = models.ForeignKey( - Employee, - on_delete=models.CASCADE, - verbose_name="Employee", - ) - date = models.DateField(default=timezone.now) - time_spent = models.CharField( - null=True, - default="00:00", - max_length=10, - validators=[validate_time_format], - verbose_name="Hours Spent", - ) - status = models.CharField( - choices=TIME_SHEET_STATUS, max_length=250, default="in_Progress" - ) - description = models.TextField(blank=True, null=True) - objects = models.Manager() - - class Meta: - ordering = ("-id",) - - def clean(self): - if self.project_id is None: - raise ValidationError({"project_id": "Project name is Required."}) - if self.description is None or self.description == "": - raise ValidationError( - {"description": "Please provide a description to your Time sheet"} - ) - if self.employee_id: - employee = self.employee_id - if self.task_id: - task = self.task_id - if ( - not employee in task.task_managers.all() - and not employee in task.task_members.all() - and not employee in task.project.managers.all() - and not employee in task.project.members.all() - ): - raise ValidationError(_("Employee not included in this task")) - elif self.project_id: - if ( - not employee in self.project_id.managers.all() - and not employee in self.project_id.members.all() - ): - raise ValidationError(_("Employee not included in this project")) - if self.date > datetime.datetime.today().date(): - raise ValidationError({"date": _("You cannot choose a future date.")}) - - def __str__(self): - return f"{self.employee_id} {self.project_id} {self.task_id} {self.date} {self.time_spent}" - - def status_column(self): - return dict(self.TIME_SHEET_STATUS).get(self.status) - - def actions(self): - """ - This method for get custom column for action. - """ - - return render_template( - path="cbv/timesheet/actions.html", - context={"instance": self}, - ) - - def detail_actions(self): - """ - This method for get custom column for action. - """ - - return render_template( - path="cbv/timesheet/detail_actions.html", - context={"instance": self}, - ) - - def get_update_url(self): - """ - This method to get update url - """ - url = reverse_lazy("update-time-sheet", kwargs={"pk": self.pk}) - return url - - def get_delete_url(self): - """ - This method to get delete url - """ - url = reverse_lazy("delete-time-sheet", kwargs={"time_sheet_id": self.pk}) - message = "Are you sure you want to delete this time sheet?" - return f"'{url}'" + "," + f"'{message}'" - - def detail_view(self): - """ - for detail view of page - """ - url = reverse("time-sheet-detail-view", kwargs={"pk": self.pk}) - return url +""" +models.py + +This module is used to register models for project app + +""" + +import datetime +from datetime import date + +from django.apps import apps +from django.core.exceptions import ValidationError +from django.db import models +from django.templatetags.static import static +from django.urls import reverse, reverse_lazy +from django.utils import timezone +from django.utils.html import format_html +from django.utils.translation import gettext_lazy as _ + +from employee.models import Employee +from horilla.horilla_middlewares import _thread_locals +from horilla_views.cbv_methods import render_template + +# Create your models here. + + +def validate_time_format(value): + """ + this method is used to validate the format of duration like fields. + """ + if len(value) > 5: + raise ValidationError(_("Invalid format, it should be HH:MM format")) + try: + hour, minute = value.split(":") + + if len(hour) < 2 or len(minute) < 2: + raise ValidationError(_("Invalid format, it should be HH:MM format")) + + minute = int(minute) + if len(hour) > 2 or minute not in range(60): + raise ValidationError(_("Invalid time")) + except ValueError as error: + raise ValidationError(_("Invalid format")) from error + + +class Project(models.Model): + PROJECT_STATUS = [ + ("new", "New"), + ("in_progress", "In Progress"), + ("completed", "Completed"), + ("on_hold", "On Hold"), + ("cancelled", "Cancelled"), + ("expired", "Expired"), + ] + title = models.CharField(max_length=200, unique=True, verbose_name="Name") + managers = models.ManyToManyField( + Employee, + blank=True, + related_name="project_managers", + verbose_name="Project Managers", + ) + members = models.ManyToManyField( + Employee, + blank=True, + related_name="project_members", + verbose_name="Project Members", + ) + status = models.CharField(choices=PROJECT_STATUS, max_length=250, default="new") + start_date = models.DateField() + end_date = models.DateField(null=True, blank=True) + document = models.FileField( + upload_to="project/files", blank=True, null=True, verbose_name="Project File" + ) + is_active = models.BooleanField(default=True) + description = models.TextField() + objects = models.Manager() + + def get_description(self, length=50): + """ + Returns a truncated version of the description attribute. + + Parameters: + length (int): The maximum length of the returned description. + """ + return ( + self.description + if len(self.description) <= length + else self.description[:length] + "..." + ) + + def get_managers(self): + """ + managers column + """ + employees = self.managers.all() + if employees: + employee_names_string = "
".join( + [str(employee) for employee in employees] + ) + return employee_names_string + + def get_members(self): + """ + members column + """ + employees = self.members.all() + if employees: + employee_names_string = "
".join( + [str(employee) for employee in employees] + ) + return employee_names_string + + def get_avatar(self): + """ + Method will retun the api to the avatar or path to the profile image + """ + url = f"https://ui-avatars.com/api/?name={self.title}&background=random" + return url + + def get_document_html(self): + if self.document: + document_url = self.document.url + image_url = static("images/ui/project/document.png") + return format_html( + '' + '' + "  View" + "", + document_url, + image_url, + ) + + def redirect(self): + """ + This method generates an onclick URL for task viewing. + """ + request = getattr(_thread_locals, "request", None) + employee = request.user.employee_get + url = reverse_lazy("task-view", kwargs={"project_id": self.pk}) + + if ( + employee in self.managers.all() + or employee in self.members.all() + or any(employee in task.task_managers.all() for task in self.task_set.all()) + or any(employee in task.task_members.all() for task in self.task_set.all()) + or request.user.has_perm("project.view_project") + ): + return f"onclick=\"window.location.href='{url}?view=list'\"" + return "" + + def get_detail_url(self): + """ + This method to get detail url + """ + url = reverse_lazy("project-detailed-view", kwargs={"pk": self.pk}) + return url + + def get_update_url(self): + """ + This method to get update url + """ + url = reverse_lazy("update-project", kwargs={"pk": self.pk}) + return url + + def get_archive_url(self): + """ + This method to get archive url + """ + url = reverse_lazy("project-archive", kwargs={"project_id": self.pk}) + return url + + def get_task_badge_html(self): + task_count = self.task_set.count() + title = self.title + return format_html( + '
' + '
' + ' ' + " {1}" + " " + "
" + "
{0}
" + "
", + title, + task_count, + ) + + def get_delete_url(self): + """ + This method to get delete url + """ + url = reverse_lazy("delete-project", kwargs={"project_id": self.pk}) + message = "Are you sure you want to delete this project?" + return f"'{url}'" + "," + f"'{message}'" + + def actions(self): + """ + This method for get custom column for action. + """ + + return render_template( + path="cbv/projects/actions.html", + context={"instance": self}, + ) + + def archive_status(self): + """ + archive status + """ + if self.is_active: + return "Archive" + else: + return "Un-Archive" + + def clean(self) -> None: + # validating end date + if self.end_date is not None: + if self.end_date < self.start_date: + raise ValidationError({"document": "End date is less than start date"}) + if self.end_date < date.today(): + self.status = "expired" + + def save(self, *args, **kwargs): + is_new = self.pk is None + super().save(*args, **kwargs) + + if is_new: + ProjectStage.objects.create( + title="Todo", + project=self, + sequence=1, + is_end_stage=False, + ) + + def __str__(self): + return self.title + + def status_column(self): + return dict(self.PROJECT_STATUS).get(self.status) + + +class ProjectStage(models.Model): + """ + ProjectStage model + """ + + title = models.CharField(max_length=200) + project = models.ForeignKey( + Project, + on_delete=models.CASCADE, + null=True, + blank=True, + related_name="project_stages", + ) + sequence = models.IntegerField(null=True, blank=True, editable=False) + is_end_stage = models.BooleanField(default=False) + + def __str__(self) -> str: + return f"{self.title}" + + def clean(self) -> None: + if self.is_end_stage: + project = self.project + existing_end_stage = project.project_stages.filter( + is_end_stage=True + ).exclude(id=self.id) + + if existing_end_stage: + end_stage = project.project_stages.filter(is_end_stage=True).first() + raise ValidationError( + _(f"Already exist an end stage - {end_stage.title}.") + ) + + def save(self, *args, **kwargs): + if self.sequence is None: + last_stage = ( + ProjectStage.objects.filter(project=self.project) + .order_by("sequence") + .last() + ) + if last_stage: + self.sequence = last_stage.sequence + 1 + super().save(*args, **kwargs) + + def delete(self, *args, **kwargs): + project_stages_after = ProjectStage.objects.filter( + project=self.project, sequence__gt=self.sequence + ) + + # Decrement the sequence of the following stages + for stage in project_stages_after: + stage.sequence -= 1 + stage.save() + + super().delete(*args, **kwargs) + + class Meta: + """ + Meta class to add the additional info + """ + + unique_together = ["project", "title"] + + +class Task(models.Model): + """ + Task model + """ + + TASK_STATUS = [ + ("to_do", "To Do"), + ("in_progress", "In Progress"), + ("completed", "Completed"), + ("expired", "Expired"), + ] + title = models.CharField(max_length=200) + project = models.ForeignKey(Project, on_delete=models.CASCADE, null=True) + stage = models.ForeignKey( + ProjectStage, + on_delete=models.CASCADE, + null=True, + related_name="tasks", + verbose_name="Project Stage", + ) + task_managers = models.ManyToManyField( + Employee, + blank=True, + verbose_name="Task Managers", + ) + task_members = models.ManyToManyField( + Employee, blank=True, related_name="tasks", verbose_name="Task Members" + ) + status = models.CharField(choices=TASK_STATUS, max_length=250, default="to_do") + start_date = models.DateField(null=True, blank=True) + end_date = models.DateField(null=True, blank=True) + document = models.FileField( + upload_to="task/files", blank=True, null=True, verbose_name="Task File" + ) + is_active = models.BooleanField(default=True) + description = models.TextField() + sequence = models.IntegerField(default=0) + objects = models.Manager() + + def clean(self) -> None: + if self.end_date is not None and self.project.end_date is not None: + if ( + self.project.end_date < self.end_date + or self.project.start_date > self.end_date + ): + raise ValidationError( + { + "end_date": _( + "The task end date must be between the project's start and end dates." + ) + } + ) + if self.end_date < date.today(): + self.status = "expired" + + class Meta: + """ + Meta class to add the additional info + """ + + unique_together = ["project", "title"] + + def __str__(self): + return f"{self.title}" + + def if_project(self): + """ + Return project if have,otherwise return none + """ + + return self.project if self.project else "None" + + def task_detail_view(self): + """ + detail view of task + """ + + url = reverse("task-detail-view", kwargs={"pk": self.pk}) + return url + + def status_column(self): + """ + to get status + """ + return dict(self.TASK_STATUS).get(self.status) + + def get_managers(self): + """ + return task managers + """ + managers = self.task_managers.all() + if managers: + managers_name_string = "
".join([str(manager) for manager in managers]) + return managers_name_string + else: + return "" + + def get_members(self): + """ + return task members + """ + members = self.task_members.all() + if members: + members_name_string = "
".join([str(member) for member in members]) + return members_name_string + else: + return "" + + def actions(self): + """ + This method for get custom column for action. + """ + # request = getattr(_thread_locals, "request", None) + # is_task_manager = self.task_manager == request.user + # print(self.title) + # is_project_manager = self.project.manager == request.user if self.project else False + # print(self.project) + # has_permission = request.user.has_perm('project.view_task') # Replace 'your_app' with your app name + + # if is_task_manager or is_project_manager or has_permission: + # return render_template( + # "cbv/tasks/task_actions.html", + # {"instance": self} + # ) + # else: + # return "" + + return render_template( + path="cbv/tasks/task_actions.html", + context={"instance": self}, + ) + + def get_avatar(self): + """ + Method will retun the api to the avatar or path to the profile image + """ + url = f"https://ui-avatars.com/api/?name={self.title}&background=random" + return url + + def document_col(self): + """ + This method for get custom document coloumn . + """ + + return render_template( + path="cbv/tasks/task_document.html", + context={"instance": self}, + ) + + def detail_view_actions(self): + """ + This method for get detail view actions. + """ + + return render_template( + path="cbv/tasks/task_detail_actions.html", + context={"instance": self}, + ) + + def get_update_url(self): + """ + to get the update url + """ + url = reverse("update-task-all", kwargs={"pk": self.pk}) + return url + + def archive_status(self): + """ + archive status + """ + if self.is_active: + return "Archive" + else: + return "Un-Archive" + + def get_archive_url(self): + """ + to get archive url + """ + + url = reverse("task-all-archive", kwargs={"task_id": self.pk}) + return url + + def get_delete_url(self): + """ + to get delete url + """ + + url = reverse("delete-task", kwargs={"task_id": self.pk}) + url_with_params = f"{url}?task_all=true" + message = "Are you sure you want to delete this task?" + return f"'{url_with_params}'" + "," + f"'{message}'" + + +class TimeSheet(models.Model): + """ + TimeSheet model + """ + + TIME_SHEET_STATUS = [ + ("in_Progress", "In Progress"), + ("completed", "Completed"), + ] + project_id = models.ForeignKey( + Project, + on_delete=models.CASCADE, + null=True, + related_name="project_timesheet", + verbose_name="Project", + ) + task_id = models.ForeignKey( + Task, + on_delete=models.CASCADE, + null=True, + related_name="task_timesheet", + verbose_name="Task", + ) + employee_id = models.ForeignKey( + Employee, + on_delete=models.CASCADE, + verbose_name="Employee", + ) + date = models.DateField(default=timezone.now) + time_spent = models.CharField( + null=True, + default="00:00", + max_length=10, + validators=[validate_time_format], + verbose_name="Hours Spent", + ) + status = models.CharField( + choices=TIME_SHEET_STATUS, max_length=250, default="in_Progress" + ) + description = models.TextField(blank=True, null=True) + objects = models.Manager() + + class Meta: + ordering = ("-id",) + + def clean(self): + if self.project_id is None: + raise ValidationError({"project_id": "Project name is Required."}) + if self.description is None or self.description == "": + raise ValidationError( + {"description": "Please provide a description to your Time sheet"} + ) + if self.employee_id: + employee = self.employee_id + if self.task_id: + task = self.task_id + if ( + not employee in task.task_managers.all() + and not employee in task.task_members.all() + and not employee in task.project.managers.all() + and not employee in task.project.members.all() + ): + raise ValidationError(_("Employee not included in this task")) + elif self.project_id: + if ( + not employee in self.project_id.managers.all() + and not employee in self.project_id.members.all() + ): + raise ValidationError(_("Employee not included in this project")) + if self.date > datetime.datetime.today().date(): + raise ValidationError({"date": _("You cannot choose a future date.")}) + + def __str__(self): + return f"{self.employee_id} {self.project_id} {self.task_id} {self.date} {self.time_spent}" + + def status_column(self): + return dict(self.TIME_SHEET_STATUS).get(self.status) + + def actions(self): + """ + This method for get custom column for action. + """ + + return render_template( + path="cbv/timesheet/actions.html", + context={"instance": self}, + ) + + def detail_actions(self): + """ + This method for get custom column for action. + """ + + return render_template( + path="cbv/timesheet/detail_actions.html", + context={"instance": self}, + ) + + def get_update_url(self): + """ + This method to get update url + """ + url = reverse_lazy("update-time-sheet", kwargs={"pk": self.pk}) + return url + + def get_delete_url(self): + """ + This method to get delete url + """ + url = reverse_lazy("delete-time-sheet", kwargs={"time_sheet_id": self.pk}) + message = "Are you sure you want to delete this time sheet?" + return f"'{url}'" + "," + f"'{message}'" + + def detail_view(self): + """ + for detail view of page + """ + url = reverse("time-sheet-detail-view", kwargs={"pk": self.pk}) + return url diff --git a/project/sidebar.py b/project/sidebar.py index fc77a8d64..82e5db5db 100644 --- a/project/sidebar.py +++ b/project/sidebar.py @@ -1,117 +1,117 @@ -""" -project/sidebar.py -""" - -from django.contrib.auth.context_processors import PermWrapper -from django.urls import reverse -from django.utils.translation import gettext_lazy as trans - -from base.templatetags.basefilters import is_reportingmanager -from project.methods import ( - any_project_manager, - any_project_member, - any_task_manager, - any_task_member, - get_all_project_members_and_managers, - has_subordinates, -) - -MENU = trans("Project") -IMG_SRC = "images/ui/project.png" -ACCESSIBILITY = "project.sidebar.menu_accessibilty" - -SUBMENUS = [ - { - "menu": trans("Dashboard"), - "redirect": reverse("project-dashboard-view"), - "accessibility": "project.sidebar.dashboard_accessibility", - }, - { - "menu": trans("Projects"), - "redirect": reverse("project-view"), - "accessibility": "project.sidebar.project_accessibility", - }, - { - "menu": trans("Tasks"), - "redirect": reverse("task-all"), - "accessibility": "project.sidebar.task_accessibility", - }, - { - "menu": trans("Timesheet"), - "redirect": reverse("view-time-sheet"), - "accessibility": "project.sidebar.timesheet_accessibility", - }, -] - - -def menu_accessibilty( - request, _menu: str = "", user_perms: PermWrapper = [], *args, **kwargs -) -> bool: - user = request.user - return ( - "project" in user_perms - # or has_subordinates(request) - or any_project_manager(user) - or any_project_member(user) - or any_task_manager(user) - or any_task_member(user) - ) - - -def dashboard_accessibility(request, submenu, user_perms, *args, **kwargs): - user = request.user - if ( - user.has_perm("project.view_project") - # or has_subordinates(request) - or is_reportingmanager(user) - or any_project_manager(user) - or any_task_manager(user) - ): - return True - else: - return False - - -def project_accessibility(request, submenu, user_perms, *args, **kwargs): - user = request.user - if ( - user.has_perm("project.view_project") - # or has_subordinates(request) - or any_project_manager(user) - or any_project_member(user) - or any_task_manager(user) - or any_task_member(user) - ): - return True - else: - return False - - -def task_accessibility(request, submenu, user_perms, *args, **kwargs): - user = request.user - if ( - user.has_perm("project.view_task") - # or has_subordinates(request) - or any_project_manager(user) - or any_project_member(user) - or any_task_manager(user) - or any_task_member(user) - ): - return True - else: - return False - - -def timesheet_accessibility(request, submenu, user_perms, *args, **kwargs): - user = request.user - if ( - user.has_perm("project.view_timesheet") - # or has_subordinates(request) - or any_project_manager(user) - or any_project_member(user) - or any_task_manager(user) - or any_task_member(user) - ): - return True - else: - return False +""" +project/sidebar.py +""" + +from django.contrib.auth.context_processors import PermWrapper +from django.urls import reverse +from django.utils.translation import gettext_lazy as trans + +from base.templatetags.basefilters import is_reportingmanager +from project.methods import ( + any_project_manager, + any_project_member, + any_task_manager, + any_task_member, + get_all_project_members_and_managers, + has_subordinates, +) + +MENU = trans("Project") +IMG_SRC = "images/ui/project.png" +ACCESSIBILITY = "project.sidebar.menu_accessibilty" + +SUBMENUS = [ + { + "menu": trans("Dashboard"), + "redirect": reverse("project-dashboard-view"), + "accessibility": "project.sidebar.dashboard_accessibility", + }, + { + "menu": trans("Projects"), + "redirect": reverse("project-view"), + "accessibility": "project.sidebar.project_accessibility", + }, + { + "menu": trans("Tasks"), + "redirect": reverse("task-all"), + "accessibility": "project.sidebar.task_accessibility", + }, + { + "menu": trans("Timesheet"), + "redirect": reverse("view-time-sheet"), + "accessibility": "project.sidebar.timesheet_accessibility", + }, +] + + +def menu_accessibilty( + request, _menu: str = "", user_perms: PermWrapper = [], *args, **kwargs +) -> bool: + user = request.user + return ( + "project" in user_perms + # or has_subordinates(request) + or any_project_manager(user) + or any_project_member(user) + or any_task_manager(user) + or any_task_member(user) + ) + + +def dashboard_accessibility(request, submenu, user_perms, *args, **kwargs): + user = request.user + if ( + user.has_perm("project.view_project") + # or has_subordinates(request) + or is_reportingmanager(user) + or any_project_manager(user) + or any_task_manager(user) + ): + return True + else: + return False + + +def project_accessibility(request, submenu, user_perms, *args, **kwargs): + user = request.user + if ( + user.has_perm("project.view_project") + # or has_subordinates(request) + or any_project_manager(user) + or any_project_member(user) + or any_task_manager(user) + or any_task_member(user) + ): + return True + else: + return False + + +def task_accessibility(request, submenu, user_perms, *args, **kwargs): + user = request.user + if ( + user.has_perm("project.view_task") + # or has_subordinates(request) + or any_project_manager(user) + or any_project_member(user) + or any_task_manager(user) + or any_task_member(user) + ): + return True + else: + return False + + +def timesheet_accessibility(request, submenu, user_perms, *args, **kwargs): + user = request.user + if ( + user.has_perm("project.view_timesheet") + # or has_subordinates(request) + or any_project_manager(user) + or any_project_member(user) + or any_task_manager(user) + or any_task_member(user) + ): + return True + else: + return False diff --git a/project/static/dashboard/projectChart.js b/project/static/dashboard/projectChart.js index 77537f183..914360899 100644 --- a/project/static/dashboard/projectChart.js +++ b/project/static/dashboard/projectChart.js @@ -1,89 +1,89 @@ -$(document).ready(function(){ - function projectStatusChart(dataSet, labels) { - const data = { - labels: labels, - datasets: dataSet, - }; - // Create chart using the Chart.js library - window['projectChart'] = {} - const ctx = document.getElementById("projectStatusCanvas").getContext("2d"); - - projectChart = new Chart(ctx, { - type: 'bar', - data: data, - options: { - }, - }); - } - $.ajax({ - url: "/project/project-status-chart", - type: "GET", - success: function (response) { - // Code to handle the response - // response = {'dataSet': [{'label': 'Odoo developer 2023-03-30', 'data': [3, 0, 5, 3]}, {'label': 'React developer 2023-03-31', 'data': [0, 1, 1, 0]}, {'label': 'Content Writer 2023-04-01', 'data': [1, 0, 0, 0]}], 'labels': ['Initial', 'Test', 'Interview', 'Hired']} - dataSet = response.dataSet; - labels = response.labels; - projectStatusChart(dataSet, labels); - - }, - }); - $('#projectStatusForward').click(function (e) { - var chartType = projectChart.config.type - if (chartType === 'line') { - chartType = 'bar'; - } else if(chartType==='bar') { - chartType = 'doughnut'; - } else if(chartType==='doughnut'){ - chartType = 'pie' - }else if(chartType==='pie'){ - chartType = 'line' - } - projectChart.config.type = chartType; - projectChart.update(); - }); - - // for creating task status chart - function taskStatusChart(dataSet, labels) { - const data = { - labels: labels, - datasets: dataSet, - }; - // Create chart using the Chart.js library - window['taskChart'] = {} - const ctx = document.getElementById("taskStatusCanvas").getContext("2d"); - - taskChart = new Chart(ctx, { - type: 'bar', - data: data, - options: { - }, - }); - } - $.ajax({ - url: "/project/task-status-chart", - type: "GET", - success: function (response) { - // Code to handle the response - // response = {'dataSet': [{'label': 'Odoo developer 2023-03-30', 'data': [3, 0, 5, 3]}, {'label': 'React developer 2023-03-31', 'data': [0, 1, 1, 0]}, {'label': 'Content Writer 2023-04-01', 'data': [1, 0, 0, 0]}], 'labels': ['Initial', 'Test', 'Interview', 'Hired']} - dataSet = response.dataSet; - labels = response.labels; - taskStatusChart(dataSet, labels); - - }, - }); - $('#taskStatusForward').click(function (e) { - var chartType = taskChart.config.type - if (chartType === 'line') { - chartType = 'bar'; - } else if(chartType==='bar') { - chartType = 'doughnut'; - } else if(chartType==='doughnut'){ - chartType = 'pie' - }else if(chartType==='pie'){ - chartType = 'line' - } - taskChart.config.type = chartType; - taskChart.update(); - }); - +$(document).ready(function(){ + function projectStatusChart(dataSet, labels) { + const data = { + labels: labels, + datasets: dataSet, + }; + // Create chart using the Chart.js library + window['projectChart'] = {} + const ctx = document.getElementById("projectStatusCanvas").getContext("2d"); + + projectChart = new Chart(ctx, { + type: 'bar', + data: data, + options: { + }, + }); + } + $.ajax({ + url: "/project/project-status-chart", + type: "GET", + success: function (response) { + // Code to handle the response + // response = {'dataSet': [{'label': 'Odoo developer 2023-03-30', 'data': [3, 0, 5, 3]}, {'label': 'React developer 2023-03-31', 'data': [0, 1, 1, 0]}, {'label': 'Content Writer 2023-04-01', 'data': [1, 0, 0, 0]}], 'labels': ['Initial', 'Test', 'Interview', 'Hired']} + dataSet = response.dataSet; + labels = response.labels; + projectStatusChart(dataSet, labels); + + }, + }); + $('#projectStatusForward').click(function (e) { + var chartType = projectChart.config.type + if (chartType === 'line') { + chartType = 'bar'; + } else if(chartType==='bar') { + chartType = 'doughnut'; + } else if(chartType==='doughnut'){ + chartType = 'pie' + }else if(chartType==='pie'){ + chartType = 'line' + } + projectChart.config.type = chartType; + projectChart.update(); + }); + + // for creating task status chart + function taskStatusChart(dataSet, labels) { + const data = { + labels: labels, + datasets: dataSet, + }; + // Create chart using the Chart.js library + window['taskChart'] = {} + const ctx = document.getElementById("taskStatusCanvas").getContext("2d"); + + taskChart = new Chart(ctx, { + type: 'bar', + data: data, + options: { + }, + }); + } + $.ajax({ + url: "/project/task-status-chart", + type: "GET", + success: function (response) { + // Code to handle the response + // response = {'dataSet': [{'label': 'Odoo developer 2023-03-30', 'data': [3, 0, 5, 3]}, {'label': 'React developer 2023-03-31', 'data': [0, 1, 1, 0]}, {'label': 'Content Writer 2023-04-01', 'data': [1, 0, 0, 0]}], 'labels': ['Initial', 'Test', 'Interview', 'Hired']} + dataSet = response.dataSet; + labels = response.labels; + taskStatusChart(dataSet, labels); + + }, + }); + $('#taskStatusForward').click(function (e) { + var chartType = taskChart.config.type + if (chartType === 'line') { + chartType = 'bar'; + } else if(chartType==='bar') { + chartType = 'doughnut'; + } else if(chartType==='doughnut'){ + chartType = 'pie' + }else if(chartType==='pie'){ + chartType = 'line' + } + taskChart.config.type = chartType; + taskChart.update(); + }); + }); diff --git a/project/static/project/import.js b/project/static/project/import.js index 9534d7a7e..a6a134b8e 100644 --- a/project/static/project/import.js +++ b/project/static/project/import.js @@ -1,309 +1,309 @@ - -var downloadMessages = { - ar: "هل ترغب في تنزيل القالب؟", - de: "Möchten Sie die Vorlage herunterladen?", - es: "¿Quieres descargar la plantilla?", - en: "Do you want to download the template?", - fr: "Voulez-vous télécharger le modèle ?", - }; - - var importsuccess = { - ar: "نجح الاستيراد", // Arabic - de: "Import erfolgreich", // German - es: "Importado con éxito", // Spanish - en: "Imported Successfully!", // English - fr: "Importation réussie" // French - }; - - var uploadsuccess = { - ar: "تحميل كامل", // Arabic - de: "Upload abgeschlossen", // German - es: "Carga completa", // Spanish - en: "Upload Complete!", // English - fr: "Téléchargement terminé" // French - }; - - var uploadingmessage = { - ar: "جارٍ الرفع", - de: "Hochladen...", - es: "Subiendo...", - en: "Uploading...", - fr: "Téléchargement en cours...", - }; - - var validationmessage = { - ar: "يرجى تحميل ملف بامتداد .xlsx فقط.", - de: "Bitte laden Sie nur eine Datei mit der Erweiterung .xlsx hoch.", - es: "Por favor, suba un archivo con la extensión .xlsx solamente.", - en: "Please upload a file with the .xlsx extension only.", - fr: "Veuillez télécharger uniquement un fichier avec l'extension .xlsx.", - }; - - function getCookie(name) { - let cookieValue = null; - if (document.cookie && document.cookie !== '') { - const cookies = document.cookie.split(';'); - for (let i = 0; i < cookies.length; i++) { - const cookie = cookies[i].trim(); - // Does this cookie string begin with the name we want? - if (cookie.substring(0, name.length + 1) === (name + '=')) { - cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); - break; - } - } - } - return cookieValue; - } - - function getCurrentLanguageCode(callback) { - $.ajax({ - type: "GET", - url: "/employee/get-language-code/", - success: function (response) { - var languageCode = response.language_code; - callback(languageCode); // Pass the language code to the callback - }, - }); - } - - - // Get the form element - var form = document.getElementById("projectImportForm"); - - // Add an event listener to the form submission - form.addEventListener("submit", function (event) { - // Prevent the default form submission - event.preventDefault(); - - // Create a new form data object - var formData = new FormData(); - - // Append the file to the form data object - var fileInput = document.querySelector("#projectImportFile"); - formData.append("file", fileInput.files[0]); - $.ajax({ - type: "POST", - url: "/project/project-import", - dataType: "binary", - data: formData, - processData: false, - contentType: false, - headers: { - "X-CSRFToken": getCookie('csrftoken'), // Replace with your csrf token value - }, - xhrFields: { - responseType: "blob", - }, - success: function (response) { - const file = new Blob([response], { - type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", - }); - const url = URL.createObjectURL(file); - const link = document.createElement("a"); - link.href = url; - link.download = "ImportError.xlsx"; - document.body.appendChild(link); - link.click(); - }, - error: function (xhr, textStatus, errorThrown) { - console.error("Error downloading file:", errorThrown); - }, - }); - }); - - - $("#importProject").click(function (e) { - e.preventDefault(); - var languageCode = null; - getCurrentLanguageCode(function (code) { - languageCode = code; - var confirmMessage = downloadMessages[languageCode]; - // Use SweetAlert for the confirmation dialog - Swal.fire({ - - text: confirmMessage, - icon: 'question', - showCancelButton: true, - confirmButtonColor: '#008000', - cancelButtonColor: '#d33', - confirmButtonText: 'Confirm' - }).then(function(result) { - if (result.isConfirmed) { - $("#loading").show(); - var xhr = new XMLHttpRequest(); - xhr.open('GET', "/project/project-import", true); - xhr.responseType = 'arraybuffer'; - - xhr.upload.onprogress = function (e) { - if (e.lengthComputable) { - var percent = (e.loaded / e.total) * 100; - $(".progress-bar").width(percent + "%").attr("aria-valuenow", percent); - $("#progress-text").text("Uploading... " + percent.toFixed(2) + "%"); - } - }; - - xhr.onload = function (e) { - if (this.status == 200) { - const file = new Blob([this.response], { - type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", - }); - const url = URL.createObjectURL(file); - const link = document.createElement("a"); - link.href = url; - link.download = "project_template.xlsx"; - document.body.appendChild(link); - link.click(); - } - }; - - xhr.onerror = function (e) { - console.error("Error downloading file:", e); - }; - - xhr.send(); - } - }); - }); - }); - - $(document).on('click', '#importProject', function (e) { - e.preventDefault(); - var languageCode = null; - getCurrentLanguageCode(function (code) { - languageCode = code; - var confirmMessage = downloadMessages[languageCode]; - // Use SweetAlert for the confirmation dialog - Swal.fire({ - text: confirmMessage, - icon: 'question', - showCancelButton: true, - confirmButtonColor: '#008000', - cancelButtonColor: '#d33', - confirmButtonText: 'Confirm' - }).then(function(result) { - if (result.isConfirmed) { - $("#loading").show(); - var xhr = new XMLHttpRequest(); - xhr.open('GET', "/project/project-import", true); - xhr.responseType = 'arraybuffer'; - - xhr.upload.onprogress = function (e) { - if (e.lengthComputable) { - var percent = (e.loaded / e.total) * 100; - $(".progress-bar").width(percent + "%").attr("aria-valuenow", percent); - $("#progress-text").text("Uploading... " + percent.toFixed(2) + "%"); - } - }; - - xhr.onload = function (e) { - if (this.status == 200) { - const file = new Blob([this.response], { - type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", - }); - const url = URL.createObjectURL(file); - const link = document.createElement("a"); - link.href = url; - link.download = "project_template.xlsx"; - document.body.appendChild(link); - link.click(); - // Clean up by removing the link element - document.body.removeChild(link); - URL.revokeObjectURL(url); - } - }; - - xhr.onerror = function (e) { - console.error("Error downloading file:", e); - }; - - xhr.send(); - } - }); - }); -}); - - - $(document).ajaxStart(function () { - $("#loading").show(); - }); - - $(document).ajaxStop(function () { - $("#loading").hide(); - }); - - function simulateProgress() { - var languageCode = null; - getCurrentLanguageCode(function(code){ - languageCode = code; - var importMessage = importsuccess[languageCode]; - var uploadMessage = uploadsuccess[languageCode]; - var uploadingMessage = uploadingmessage[languageCode]; - let progressBar = document.querySelector('.progress-bar'); - let progressText = document.getElementById('progress-text'); - - let width = 0; - let interval = setInterval(function() { - if (width >= 100) { - clearInterval(interval); - progressText.innerText = uploadMessage; - setTimeout(function() { - document.getElementById('loading').style.display = 'none'; - }, 3000); - Swal.fire({ - text: importMessage, - icon: "success", - showConfirmButton: false, - timer: 2000, - timerProgressBar: true, - }); - setTimeout(function() { - $('#projectImport').removeClass('oh-modal--show'); - location.reload(true); - }, 2000); - } else { - width++; - progressBar.style.width = width + '%'; - progressBar.setAttribute('aria-valuenow', width); - progressText.innerText = uploadingMessage + width + '%'; - } - }, 20); - } - )} - - document.getElementById('projectImportForm').addEventListener('submit', function(event) { - event.preventDefault(); - var languageCode = null; - getCurrentLanguageCode(function(code){ - languageCode = code; - var erroMessage = validationmessage[languageCode]; - - var fileInput = $('#projectImportFile').val(); - var allowedExtensions = /(\.xlsx)$/i; - - if (!allowedExtensions.exec(fileInput)) { - - var errorMessage = document.createElement('div'); - errorMessage.classList.add('error-message'); - - errorMessage.textContent = erroMessage; - - document.getElementById('error-container').appendChild(errorMessage); - - fileInput.value = ''; - - setTimeout(function() { - errorMessage.remove(); - }, 2000); - - return false; - } - else{ - - document.getElementById('loading').style.display = 'block'; - - - simulateProgress(); - } - - }); - }) + +var downloadMessages = { + ar: "هل ترغب في تنزيل القالب؟", + de: "Möchten Sie die Vorlage herunterladen?", + es: "¿Quieres descargar la plantilla?", + en: "Do you want to download the template?", + fr: "Voulez-vous télécharger le modèle ?", + }; + + var importsuccess = { + ar: "نجح الاستيراد", // Arabic + de: "Import erfolgreich", // German + es: "Importado con éxito", // Spanish + en: "Imported Successfully!", // English + fr: "Importation réussie" // French + }; + + var uploadsuccess = { + ar: "تحميل كامل", // Arabic + de: "Upload abgeschlossen", // German + es: "Carga completa", // Spanish + en: "Upload Complete!", // English + fr: "Téléchargement terminé" // French + }; + + var uploadingmessage = { + ar: "جارٍ الرفع", + de: "Hochladen...", + es: "Subiendo...", + en: "Uploading...", + fr: "Téléchargement en cours...", + }; + + var validationmessage = { + ar: "يرجى تحميل ملف بامتداد .xlsx فقط.", + de: "Bitte laden Sie nur eine Datei mit der Erweiterung .xlsx hoch.", + es: "Por favor, suba un archivo con la extensión .xlsx solamente.", + en: "Please upload a file with the .xlsx extension only.", + fr: "Veuillez télécharger uniquement un fichier avec l'extension .xlsx.", + }; + + function getCookie(name) { + let cookieValue = null; + if (document.cookie && document.cookie !== '') { + const cookies = document.cookie.split(';'); + for (let i = 0; i < cookies.length; i++) { + const cookie = cookies[i].trim(); + // Does this cookie string begin with the name we want? + if (cookie.substring(0, name.length + 1) === (name + '=')) { + cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); + break; + } + } + } + return cookieValue; + } + + function getCurrentLanguageCode(callback) { + $.ajax({ + type: "GET", + url: "/employee/get-language-code/", + success: function (response) { + var languageCode = response.language_code; + callback(languageCode); // Pass the language code to the callback + }, + }); + } + + + // Get the form element + var form = document.getElementById("projectImportForm"); + + // Add an event listener to the form submission + form.addEventListener("submit", function (event) { + // Prevent the default form submission + event.preventDefault(); + + // Create a new form data object + var formData = new FormData(); + + // Append the file to the form data object + var fileInput = document.querySelector("#projectImportFile"); + formData.append("file", fileInput.files[0]); + $.ajax({ + type: "POST", + url: "/project/project-import", + dataType: "binary", + data: formData, + processData: false, + contentType: false, + headers: { + "X-CSRFToken": getCookie('csrftoken'), // Replace with your csrf token value + }, + xhrFields: { + responseType: "blob", + }, + success: function (response) { + const file = new Blob([response], { + type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + }); + const url = URL.createObjectURL(file); + const link = document.createElement("a"); + link.href = url; + link.download = "ImportError.xlsx"; + document.body.appendChild(link); + link.click(); + }, + error: function (xhr, textStatus, errorThrown) { + console.error("Error downloading file:", errorThrown); + }, + }); + }); + + + $("#importProject").click(function (e) { + e.preventDefault(); + var languageCode = null; + getCurrentLanguageCode(function (code) { + languageCode = code; + var confirmMessage = downloadMessages[languageCode]; + // Use SweetAlert for the confirmation dialog + Swal.fire({ + + text: confirmMessage, + icon: 'question', + showCancelButton: true, + confirmButtonColor: '#008000', + cancelButtonColor: '#d33', + confirmButtonText: 'Confirm' + }).then(function(result) { + if (result.isConfirmed) { + $("#loading").show(); + var xhr = new XMLHttpRequest(); + xhr.open('GET', "/project/project-import", true); + xhr.responseType = 'arraybuffer'; + + xhr.upload.onprogress = function (e) { + if (e.lengthComputable) { + var percent = (e.loaded / e.total) * 100; + $(".progress-bar").width(percent + "%").attr("aria-valuenow", percent); + $("#progress-text").text("Uploading... " + percent.toFixed(2) + "%"); + } + }; + + xhr.onload = function (e) { + if (this.status == 200) { + const file = new Blob([this.response], { + type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + }); + const url = URL.createObjectURL(file); + const link = document.createElement("a"); + link.href = url; + link.download = "project_template.xlsx"; + document.body.appendChild(link); + link.click(); + } + }; + + xhr.onerror = function (e) { + console.error("Error downloading file:", e); + }; + + xhr.send(); + } + }); + }); + }); + + $(document).on('click', '#importProject', function (e) { + e.preventDefault(); + var languageCode = null; + getCurrentLanguageCode(function (code) { + languageCode = code; + var confirmMessage = downloadMessages[languageCode]; + // Use SweetAlert for the confirmation dialog + Swal.fire({ + text: confirmMessage, + icon: 'question', + showCancelButton: true, + confirmButtonColor: '#008000', + cancelButtonColor: '#d33', + confirmButtonText: 'Confirm' + }).then(function(result) { + if (result.isConfirmed) { + $("#loading").show(); + var xhr = new XMLHttpRequest(); + xhr.open('GET', "/project/project-import", true); + xhr.responseType = 'arraybuffer'; + + xhr.upload.onprogress = function (e) { + if (e.lengthComputable) { + var percent = (e.loaded / e.total) * 100; + $(".progress-bar").width(percent + "%").attr("aria-valuenow", percent); + $("#progress-text").text("Uploading... " + percent.toFixed(2) + "%"); + } + }; + + xhr.onload = function (e) { + if (this.status == 200) { + const file = new Blob([this.response], { + type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + }); + const url = URL.createObjectURL(file); + const link = document.createElement("a"); + link.href = url; + link.download = "project_template.xlsx"; + document.body.appendChild(link); + link.click(); + // Clean up by removing the link element + document.body.removeChild(link); + URL.revokeObjectURL(url); + } + }; + + xhr.onerror = function (e) { + console.error("Error downloading file:", e); + }; + + xhr.send(); + } + }); + }); +}); + + + $(document).ajaxStart(function () { + $("#loading").show(); + }); + + $(document).ajaxStop(function () { + $("#loading").hide(); + }); + + function simulateProgress() { + var languageCode = null; + getCurrentLanguageCode(function(code){ + languageCode = code; + var importMessage = importsuccess[languageCode]; + var uploadMessage = uploadsuccess[languageCode]; + var uploadingMessage = uploadingmessage[languageCode]; + let progressBar = document.querySelector('.progress-bar'); + let progressText = document.getElementById('progress-text'); + + let width = 0; + let interval = setInterval(function() { + if (width >= 100) { + clearInterval(interval); + progressText.innerText = uploadMessage; + setTimeout(function() { + document.getElementById('loading').style.display = 'none'; + }, 3000); + Swal.fire({ + text: importMessage, + icon: "success", + showConfirmButton: false, + timer: 2000, + timerProgressBar: true, + }); + setTimeout(function() { + $('#projectImport').removeClass('oh-modal--show'); + location.reload(true); + }, 2000); + } else { + width++; + progressBar.style.width = width + '%'; + progressBar.setAttribute('aria-valuenow', width); + progressText.innerText = uploadingMessage + width + '%'; + } + }, 20); + } + )} + + document.getElementById('projectImportForm').addEventListener('submit', function(event) { + event.preventDefault(); + var languageCode = null; + getCurrentLanguageCode(function(code){ + languageCode = code; + var erroMessage = validationmessage[languageCode]; + + var fileInput = $('#projectImportFile').val(); + var allowedExtensions = /(\.xlsx)$/i; + + if (!allowedExtensions.exec(fileInput)) { + + var errorMessage = document.createElement('div'); + errorMessage.classList.add('error-message'); + + errorMessage.textContent = erroMessage; + + document.getElementById('error-container').appendChild(errorMessage); + + fileInput.value = ''; + + setTimeout(function() { + errorMessage.remove(); + }, 2000); + + return false; + } + else{ + + document.getElementById('loading').style.display = 'block'; + + + simulateProgress(); + } + + }); + }) diff --git a/project/static/project/project_action.js b/project/static/project/project_action.js index 1f5c66a91..5f31947fa 100644 --- a/project/static/project/project_action.js +++ b/project/static/project/project_action.js @@ -1,631 +1,631 @@ -var archiveMessagesSelected = { - // ar: "هل ترغب حقًا في أرشفة جميع الموظفين المحددين؟", - // de: "Möchten Sie wirklich alle ausgewählten Mitarbeiter archivieren?", - // es: "¿Realmente quieres archivar a todos los empleados seleccionados?", - en: "Do you really want to archive all the selected projects?", - // fr: "Voulez-vous vraiment archiver tous les employés sélectionnés ?", - }; - - var unarchiveMessagesSelected = { - // ar: "هل ترغب حقًا في إلغاء أرشفة جميع الموظفين المحددين؟", - // de: "Möchten Sie wirklich alle ausgewählten Mitarbeiter aus der Archivierung zurückholen?", - // es: "¿Realmente quieres desarchivar a todos los empleados seleccionados?", - en: "Do you really want to unarchive all the selected projects?", - // fr: "Voulez-vous vraiment désarchiver tous les employés sélectionnés?", - }; - - var deleteMessage = { - // ar: "هل ترغب حقًا في حذف جميع الموظفين المحددين؟", - // de: "Möchten Sie wirklich alle ausgewählten Mitarbeiter löschen?", - // es: "¿Realmente quieres eliminar a todos los empleados seleccionados?", - en: "Do you really want to delete all the selected projects?", - // fr: "Voulez-vous vraiment supprimer tous les employés sélectionnés?", - }; - - var exportMessages = { - // ar: "هل ترغب حقًا في حذف جميع الموظفين المحددين؟", - // de: "Möchten Sie wirklich alle ausgewählten Mitarbeiter löschen?", - // es: "¿Realmente quieres eliminar a todos los empleados seleccionados?", - en: "Do you really want to export all the selected projects?", - // fr: "Voulez-vous vraiment supprimer tous les employés sélectionnés?", - }; - - var downloadMessages = { - ar: "هل ترغب في تنزيل القالب؟", - de: "Möchten Sie die Vorlage herunterladen?", - es: "¿Quieres descargar la plantilla?", - en: "Do you want to download the template?", - fr: "Voulez-vous télécharger le modèle ?", - }; - - var norowMessagesSelected = { - // ar: "لم يتم تحديد أي صفوف.", - // de: "Es wurden keine Zeilen ausgewählt.", - // es: "No se han seleccionado filas.", - en: "No rows have been selected.", - // fr: "Aucune ligne n'a été sélectionnée.", - }; - - function getCookie(name) { - let cookieValue = null; - if (document.cookie && document.cookie !== "") { - const cookies = document.cookie.split(";"); - for (let i = 0; i < cookies.length; i++) { - const cookie = cookies[i].trim(); - // Does this cookie string begin with the name we want? - if (cookie.substring(0, name.length + 1) === name + "=") { - cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); - break; - } - } - } - return cookieValue; - } - - function getCurrentLanguageCode(callback) { - $.ajax({ - type: "GET", - url: "/employee/get-language-code/", - success: function (response) { - var languageCode = response.language_code; - callback(languageCode); // Pass the language code to the callback - }, - }); - } - - - // // Get the form element - // var form = document.getElementById("projectImportForm"); - - // // Add an event listener to the form submission - // form.addEventListener("submit", function (event) { - // // Prevent the default form submission - // event.preventDefault(); - - // // Create a new form data object - // var formData = new FormData(); - - // // Append the file to the form data object - // var fileInput = document.querySelector("#projectImportFile"); - // formData.append("file", fileInput.files[0]); - // $.ajax({ - // type: "POST", - // url: "/project/project-import", - // dataType: "binary", - // data: formData, - // processData: false, - // contentType: false, - // headers: { - // "X-CSRFToken": getCookie('csrftoken'), // Replace with your csrf token value - // }, - // xhrFields: { - // responseType: "blob", - // }, - // success: function (response) { - // const file = new Blob([response], { - // type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", - // }); - // const url = URL.createObjectURL(file); - // const link = document.createElement("a"); - // link.href = url; - // link.download = "ImportError.xlsx"; - // document.body.appendChild(link); - // link.click(); - // }, - // error: function (xhr, textStatus, errorThrown) { - // console.error("Error downloading file:", errorThrown); - // }, - // }); - // }); - - // $("#importProject").click(function (e) { - // e.preventDefault(); - // var languageCode = null; - // getCurrentLanguageCode(function (code) { - // languageCode = code; - // var confirmMessage = downloadMessages[languageCode]; - // // Use SweetAlert for the confirmation dialog - // Swal.fire({ - // text: confirmMessage, - // icon: 'question', - // showCancelButton: true, - // confirmButtonColor: '#008000', - // cancelButtonColor: '#d33', - // confirmButtonText: 'Confirm' - // }).then(function(result) { - // if (result.isConfirmed) { - // $.ajax({ - // type: "GET", - // url: "/project/project-import", - // dataType: "binary", - // xhrFields: { - // responseType: "blob", - // }, - // success: function (response) { - // const file = new Blob([response], { - // type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", - // }); - // const url = URL.createObjectURL(file); - // const link = document.createElement("a"); - // link.href = url; - // link.download = "project_template.xlsx"; - // document.body.appendChild(link); - // link.click(); - // }, - // error: function (xhr, textStatus, errorThrown) { - // console.error("Error downloading file:", errorThrown); - // }, - // }); - // } - // }); - // }); - // }); - - // $('#importProject').click(function (e) { - // $.ajax({ - // type: 'POST', - // url: '/project/project-import', - // dataType: 'binary', - // xhrFields: { - // responseType: 'blob' - // }, - // success: function(response) { - // const file = new Blob([response], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'}); - // const url = URL.createObjectURL(file); - // const link = document.createElement('a'); - // link.href = url; - // link.download = 'project.xlsx'; - // document.body.appendChild(link); - // link.click(); - // }, - // error: function(xhr, textStatus, errorThrown) { - // console.error('Error downloading file:', errorThrown); - // } - // }); - // }); - - - $(".all-projects").change(function (e) { - var is_checked = $(this).is(":checked"); - if (is_checked) { - $(".all-project-row").prop("checked", true); - } else { - $(".all-project-row").prop("checked", false); - } - }); - - $("#exportProject").click(function (e) { - e.preventDefault(); - var languageCode = null; - getCurrentLanguageCode(function (code) { - languageCode = code; - var confirmMessage = exportMessages[languageCode]; - var textMessage = norowMessagesSelected[languageCode]; - var checkedRows = $(".all-project-row").filter(":checked"); - if (checkedRows.length === 0) { - Swal.fire({ - text: textMessage, - icon: "warning", - confirmButtonText: "Close", - }); - } else { - Swal.fire({ - text: confirmMessage, - icon: "info", - showCancelButton: true, - confirmButtonColor: "#008000", - cancelButtonColor: "#d33", - confirmButtonText: "Confirm", - }).then(function (result) { - if (result.isConfirmed) { - var checkedRows = $(".all-project-row").filter(":checked"); - ids = []; - checkedRows.each(function () { - ids.push($(this).attr("id")); - }); - - $.ajax({ - type: "POST", - url: "/project/project-bulk-export", - dataType: "binary", - xhrFields: { - responseType: "blob", - }, - data: { - csrfmiddlewaretoken: getCookie("csrftoken"), - ids: JSON.stringify(ids), - }, - success: function (response, textStatus, jqXHR) { - const file = new Blob([response], { - type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", - }); - const url = URL.createObjectURL(file); - const link = document.createElement("a"); - link.href = url; - link.download = "project details.xlsx"; - document.body.appendChild(link); - link.click(); - }, - }); - } - }); - } - }); - }); - - $(document).on('click', '#exportProject', function (e) { - e.preventDefault(); - var languageCode = null; - getCurrentLanguageCode(function (code) { - languageCode = code; - var confirmMessage = exportMessages[languageCode]; - var textMessage = norowMessagesSelected[languageCode]; - ids = []; - ids.push($("#selectedInstances").attr("data-ids")); - ids = JSON.parse($("#selectedInstances").attr("data-ids")); - if (ids.length === 0) { - Swal.fire({ - text: textMessage, - icon: "warning", - confirmButtonText: "Close", - }); - } else { - Swal.fire({ - text: confirmMessage, - icon: "info", - showCancelButton: true, - confirmButtonColor: "#008000", - cancelButtonColor: "#d33", - confirmButtonText: "Confirm", - }).then(function (result) { - if (result.isConfirmed) { - // var checkedRows = $(".all-project-row").filter(":checked"); - // ids = []; - // checkedRows.each(function () { - // ids.push($(this).attr("id")); - // }); - - $.ajax({ - type: "POST", - url: "/project/project-bulk-export", - dataType: "binary", - xhrFields: { - responseType: "blob", - }, - data: { - csrfmiddlewaretoken: getCookie("csrftoken"), - ids: JSON.stringify(ids), - }, - success: function (response, textStatus, jqXHR) { - const file = new Blob([response], { - type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", - }); - const url = URL.createObjectURL(file); - const link = document.createElement("a"); - link.href = url; - link.download = "project details.xlsx"; - document.body.appendChild(link); - link.click(); - }, - }); - } - }); - } - }); - }); - - - $("#archiveProject").click(function (e) { - e.preventDefault(); - var languageCode = null; - getCurrentLanguageCode(function (code) { - languageCode = code; - var confirmMessage = archiveMessagesSelected[languageCode]; - var textMessage = norowMessagesSelected[languageCode]; - var checkedRows = $(".all-project-row").filter(":checked"); - if (checkedRows.length === 0) { - Swal.fire({ - text: textMessage, - icon: "warning", - confirmButtonText: "Close", - }); - } else { - Swal.fire({ - text: confirmMessage, - icon: "info", - showCancelButton: true, - confirmButtonColor: "#008000", - cancelButtonColor: "#d33", - confirmButtonText: "Confirm", - }).then(function (result) { - if (result.isConfirmed) { - e.preventDefault(); - ids = []; - checkedRows.each(function () { - ids.push($(this).attr("id")); - }); - - $.ajax({ - type: "POST", - url: "/project/project-bulk-archive?is_active=False", - data: { - csrfmiddlewaretoken: getCookie("csrftoken"), - ids: JSON.stringify(ids), - }, - success: function (response, textStatus, jqXHR) { - if (jqXHR.status === 200) { - location.reload(); // Reload the current page - } else { - // console.log("Unexpected HTTP status:", jqXHR.status); - } - }, - }); - } - }); - } - }); - }); - - - $(document).on('click', '#archiveProject', function (e) { - e.preventDefault(); - var languageCode = null; - getCurrentLanguageCode(function (code) { - languageCode = code; - var confirmMessage = archiveMessagesSelected[languageCode]; - var textMessage = norowMessagesSelected[languageCode]; - ids = []; - ids.push($("#selectedInstances").attr("data-ids")); - ids = JSON.parse($("#selectedInstances").attr("data-ids")); - if (ids.length === 0) { - Swal.fire({ - text: textMessage, - icon: "warning", - confirmButtonText: "Close", - }); - } else { - Swal.fire({ - text: confirmMessage, - icon: "info", - showCancelButton: true, - confirmButtonColor: "#008000", - cancelButtonColor: "#d33", - confirmButtonText: "Confirm", - }).then(function (result) { - if (result.isConfirmed) { - // e.preventDefault(); - // ids = []; - // checkedRows.each(function () { - // ids.push($(this).attr("id")); - // }); - - $.ajax({ - type: "POST", - url: "/project/project-bulk-archive?is_active=False", - data: { - csrfmiddlewaretoken: getCookie("csrftoken"), - ids: JSON.stringify(ids), - }, - success: function (response, textStatus, jqXHR) { - if (jqXHR.status === 200) { - location.reload(); // Reload the current page - } else { - // console.log("Unexpected HTTP status:", jqXHR.status); - } - }, - }); - } - }); - } - }); - }); - - -$("#unArchiveProject").click(function (e) { - e.preventDefault(); - var languageCode = null; - getCurrentLanguageCode(function (code) { - languageCode = code; - var confirmMessage = unarchiveMessagesSelected[languageCode]; - var textMessage = norowMessagesSelected[languageCode]; - var checkedRows = $(".all-project-row").filter(":checked"); - if (checkedRows.length === 0) { - Swal.fire({ - text: textMessage, - icon: "warning", - confirmButtonText: "Close", - }); - } else { - Swal.fire({ - text: confirmMessage, - icon: "info", - showCancelButton: true, - confirmButtonColor: "#008000", - cancelButtonColor: "#d33", - confirmButtonText: "Confirm", - }).then(function (result) { - if (result.isConfirmed) { - var checkedRows = $(".all-project-row").filter(":checked"); - ids = []; - checkedRows.each(function () { - ids.push($(this).attr("id")); - }); - - $.ajax({ - type: "POST", - url: "/project/project-bulk-archive?is_active=True", - data: { - csrfmiddlewaretoken: getCookie("csrftoken"), - ids: JSON.stringify(ids), - }, - success: function (response, textStatus, jqXHR) { - if (jqXHR.status === 200) { - location.reload(); // Reload the current page - } else { - // console.log("Unexpected HTTP status:", jqXHR.status); - } - }, - }); - } - }); - } - }); - }); - - $(document).on('click', '#unArchiveProject', function (e) { - e.preventDefault(); - var languageCode = null; - getCurrentLanguageCode(function (code) { - languageCode = code; - var confirmMessage = unarchiveMessagesSelected[languageCode]; - var textMessage = norowMessagesSelected[languageCode]; - ids = []; - ids.push($("#selectedInstances").attr("data-ids")); - ids = JSON.parse($("#selectedInstances").attr("data-ids")); - if (ids.length === 0) { - Swal.fire({ - text: textMessage, - icon: "warning", - confirmButtonText: "Close", - }); - } else { - Swal.fire({ - text: confirmMessage, - icon: "info", - showCancelButton: true, - confirmButtonColor: "#008000", - cancelButtonColor: "#d33", - confirmButtonText: "Confirm", - }).then(function (result) { - if (result.isConfirmed) { - // var checkedRows = $(".all-project-row").filter(":checked"); - // ids = []; - // checkedRows.each(function () { - // ids.push($(this).attr("id")); - // }); - - $.ajax({ - type: "POST", - url: "/project/project-bulk-archive?is_active=True", - data: { - csrfmiddlewaretoken: getCookie("csrftoken"), - ids: JSON.stringify(ids), - }, - success: function (response, textStatus, jqXHR) { - if (jqXHR.status === 200) { - location.reload(); // Reload the current page - } else { - // console.log("Unexpected HTTP status:", jqXHR.status); - } - }, - }); - } - }); - } - }); - }); - -$("#deleteProject").click(function (e) { - e.preventDefault(); - var languageCode = null; - getCurrentLanguageCode(function (code) { - languageCode = code; - var confirmMessage = deleteMessage[languageCode]; - var textMessage = norowMessagesSelected[languageCode]; - var checkedRows = $(".all-project-row").filter(":checked"); - if (checkedRows.length === 0) { - Swal.fire({ - text: textMessage, - icon: "warning", - confirmButtonText: "Close", - }); - } else { - Swal.fire({ - text: confirmMessage, - icon: "error", - showCancelButton: true, - confirmButtonColor: "#008000", - cancelButtonColor: "#d33", - confirmButtonText: "Confirm", - }).then(function (result) { - if (result.isConfirmed) { - var checkedRows = $(".all-project-row").filter(":checked"); - ids = []; - checkedRows.each(function () { - ids.push($(this).attr("id")); - }); - - $.ajax({ - type: "POST", - url: "/project/project-bulk-delete", - data: { - csrfmiddlewaretoken: getCookie("csrftoken"), - ids: JSON.stringify(ids), - }, - success: function (response, textStatus, jqXHR) { - if (jqXHR.status === 200) { - location.reload(); // Reload the current page - } else { - // console.log("Unexpected HTTP status:", jqXHR.status); - } - }, - }); - } - }); - } - }); - }); - - - $(document).on('click', '#deleteProject', function (e) { - e.preventDefault(); - var languageCode = null; - getCurrentLanguageCode(function (code) { - languageCode = code; - var confirmMessage = deleteMessage[languageCode]; - var textMessage = norowMessagesSelected[languageCode]; - ids = []; - ids.push($("#selectedInstances").attr("data-ids")); - ids = JSON.parse($("#selectedInstances").attr("data-ids")); - if (ids.length === 0) { - Swal.fire({ - text: textMessage, - icon: "warning", - confirmButtonText: "Close", - }); - } else { - Swal.fire({ - text: confirmMessage, - icon: "error", - showCancelButton: true, - confirmButtonColor: "#008000", - cancelButtonColor: "#d33", - confirmButtonText: "Confirm", - }).then(function (result) { - if (result.isConfirmed) { - // var checkedRows = $(".all-project-row").filter(":checked"); - // ids = []; - // checkedRows.each(function () { - // ids.push($(this).attr("id")); - // }); - - $.ajax({ - type: "POST", - url: "/project/project-bulk-delete", - data: { - csrfmiddlewaretoken: getCookie("csrftoken"), - ids: JSON.stringify(ids), - }, - success: function (response, textStatus, jqXHR) { - if (jqXHR.status === 200) { - location.reload(); // Reload the current page - } else { - // console.log("Unexpected HTTP status:", jqXHR.status); - } - }, - }); - } - }); - } - }); +var archiveMessagesSelected = { + // ar: "هل ترغب حقًا في أرشفة جميع الموظفين المحددين؟", + // de: "Möchten Sie wirklich alle ausgewählten Mitarbeiter archivieren?", + // es: "¿Realmente quieres archivar a todos los empleados seleccionados?", + en: "Do you really want to archive all the selected projects?", + // fr: "Voulez-vous vraiment archiver tous les employés sélectionnés ?", + }; + + var unarchiveMessagesSelected = { + // ar: "هل ترغب حقًا في إلغاء أرشفة جميع الموظفين المحددين؟", + // de: "Möchten Sie wirklich alle ausgewählten Mitarbeiter aus der Archivierung zurückholen?", + // es: "¿Realmente quieres desarchivar a todos los empleados seleccionados?", + en: "Do you really want to unarchive all the selected projects?", + // fr: "Voulez-vous vraiment désarchiver tous les employés sélectionnés?", + }; + + var deleteMessage = { + // ar: "هل ترغب حقًا في حذف جميع الموظفين المحددين؟", + // de: "Möchten Sie wirklich alle ausgewählten Mitarbeiter löschen?", + // es: "¿Realmente quieres eliminar a todos los empleados seleccionados?", + en: "Do you really want to delete all the selected projects?", + // fr: "Voulez-vous vraiment supprimer tous les employés sélectionnés?", + }; + + var exportMessages = { + // ar: "هل ترغب حقًا في حذف جميع الموظفين المحددين؟", + // de: "Möchten Sie wirklich alle ausgewählten Mitarbeiter löschen?", + // es: "¿Realmente quieres eliminar a todos los empleados seleccionados?", + en: "Do you really want to export all the selected projects?", + // fr: "Voulez-vous vraiment supprimer tous les employés sélectionnés?", + }; + + var downloadMessages = { + ar: "هل ترغب في تنزيل القالب؟", + de: "Möchten Sie die Vorlage herunterladen?", + es: "¿Quieres descargar la plantilla?", + en: "Do you want to download the template?", + fr: "Voulez-vous télécharger le modèle ?", + }; + + var norowMessagesSelected = { + // ar: "لم يتم تحديد أي صفوف.", + // de: "Es wurden keine Zeilen ausgewählt.", + // es: "No se han seleccionado filas.", + en: "No rows have been selected.", + // fr: "Aucune ligne n'a été sélectionnée.", + }; + + function getCookie(name) { + let cookieValue = null; + if (document.cookie && document.cookie !== "") { + const cookies = document.cookie.split(";"); + for (let i = 0; i < cookies.length; i++) { + const cookie = cookies[i].trim(); + // Does this cookie string begin with the name we want? + if (cookie.substring(0, name.length + 1) === name + "=") { + cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); + break; + } + } + } + return cookieValue; + } + + function getCurrentLanguageCode(callback) { + $.ajax({ + type: "GET", + url: "/employee/get-language-code/", + success: function (response) { + var languageCode = response.language_code; + callback(languageCode); // Pass the language code to the callback + }, + }); + } + + + // // Get the form element + // var form = document.getElementById("projectImportForm"); + + // // Add an event listener to the form submission + // form.addEventListener("submit", function (event) { + // // Prevent the default form submission + // event.preventDefault(); + + // // Create a new form data object + // var formData = new FormData(); + + // // Append the file to the form data object + // var fileInput = document.querySelector("#projectImportFile"); + // formData.append("file", fileInput.files[0]); + // $.ajax({ + // type: "POST", + // url: "/project/project-import", + // dataType: "binary", + // data: formData, + // processData: false, + // contentType: false, + // headers: { + // "X-CSRFToken": getCookie('csrftoken'), // Replace with your csrf token value + // }, + // xhrFields: { + // responseType: "blob", + // }, + // success: function (response) { + // const file = new Blob([response], { + // type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + // }); + // const url = URL.createObjectURL(file); + // const link = document.createElement("a"); + // link.href = url; + // link.download = "ImportError.xlsx"; + // document.body.appendChild(link); + // link.click(); + // }, + // error: function (xhr, textStatus, errorThrown) { + // console.error("Error downloading file:", errorThrown); + // }, + // }); + // }); + + // $("#importProject").click(function (e) { + // e.preventDefault(); + // var languageCode = null; + // getCurrentLanguageCode(function (code) { + // languageCode = code; + // var confirmMessage = downloadMessages[languageCode]; + // // Use SweetAlert for the confirmation dialog + // Swal.fire({ + // text: confirmMessage, + // icon: 'question', + // showCancelButton: true, + // confirmButtonColor: '#008000', + // cancelButtonColor: '#d33', + // confirmButtonText: 'Confirm' + // }).then(function(result) { + // if (result.isConfirmed) { + // $.ajax({ + // type: "GET", + // url: "/project/project-import", + // dataType: "binary", + // xhrFields: { + // responseType: "blob", + // }, + // success: function (response) { + // const file = new Blob([response], { + // type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + // }); + // const url = URL.createObjectURL(file); + // const link = document.createElement("a"); + // link.href = url; + // link.download = "project_template.xlsx"; + // document.body.appendChild(link); + // link.click(); + // }, + // error: function (xhr, textStatus, errorThrown) { + // console.error("Error downloading file:", errorThrown); + // }, + // }); + // } + // }); + // }); + // }); + + // $('#importProject').click(function (e) { + // $.ajax({ + // type: 'POST', + // url: '/project/project-import', + // dataType: 'binary', + // xhrFields: { + // responseType: 'blob' + // }, + // success: function(response) { + // const file = new Blob([response], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'}); + // const url = URL.createObjectURL(file); + // const link = document.createElement('a'); + // link.href = url; + // link.download = 'project.xlsx'; + // document.body.appendChild(link); + // link.click(); + // }, + // error: function(xhr, textStatus, errorThrown) { + // console.error('Error downloading file:', errorThrown); + // } + // }); + // }); + + + $(".all-projects").change(function (e) { + var is_checked = $(this).is(":checked"); + if (is_checked) { + $(".all-project-row").prop("checked", true); + } else { + $(".all-project-row").prop("checked", false); + } + }); + + $("#exportProject").click(function (e) { + e.preventDefault(); + var languageCode = null; + getCurrentLanguageCode(function (code) { + languageCode = code; + var confirmMessage = exportMessages[languageCode]; + var textMessage = norowMessagesSelected[languageCode]; + var checkedRows = $(".all-project-row").filter(":checked"); + if (checkedRows.length === 0) { + Swal.fire({ + text: textMessage, + icon: "warning", + confirmButtonText: "Close", + }); + } else { + Swal.fire({ + text: confirmMessage, + icon: "info", + showCancelButton: true, + confirmButtonColor: "#008000", + cancelButtonColor: "#d33", + confirmButtonText: "Confirm", + }).then(function (result) { + if (result.isConfirmed) { + var checkedRows = $(".all-project-row").filter(":checked"); + ids = []; + checkedRows.each(function () { + ids.push($(this).attr("id")); + }); + + $.ajax({ + type: "POST", + url: "/project/project-bulk-export", + dataType: "binary", + xhrFields: { + responseType: "blob", + }, + data: { + csrfmiddlewaretoken: getCookie("csrftoken"), + ids: JSON.stringify(ids), + }, + success: function (response, textStatus, jqXHR) { + const file = new Blob([response], { + type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + }); + const url = URL.createObjectURL(file); + const link = document.createElement("a"); + link.href = url; + link.download = "project details.xlsx"; + document.body.appendChild(link); + link.click(); + }, + }); + } + }); + } + }); + }); + + $(document).on('click', '#exportProject', function (e) { + e.preventDefault(); + var languageCode = null; + getCurrentLanguageCode(function (code) { + languageCode = code; + var confirmMessage = exportMessages[languageCode]; + var textMessage = norowMessagesSelected[languageCode]; + ids = []; + ids.push($("#selectedInstances").attr("data-ids")); + ids = JSON.parse($("#selectedInstances").attr("data-ids")); + if (ids.length === 0) { + Swal.fire({ + text: textMessage, + icon: "warning", + confirmButtonText: "Close", + }); + } else { + Swal.fire({ + text: confirmMessage, + icon: "info", + showCancelButton: true, + confirmButtonColor: "#008000", + cancelButtonColor: "#d33", + confirmButtonText: "Confirm", + }).then(function (result) { + if (result.isConfirmed) { + // var checkedRows = $(".all-project-row").filter(":checked"); + // ids = []; + // checkedRows.each(function () { + // ids.push($(this).attr("id")); + // }); + + $.ajax({ + type: "POST", + url: "/project/project-bulk-export", + dataType: "binary", + xhrFields: { + responseType: "blob", + }, + data: { + csrfmiddlewaretoken: getCookie("csrftoken"), + ids: JSON.stringify(ids), + }, + success: function (response, textStatus, jqXHR) { + const file = new Blob([response], { + type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + }); + const url = URL.createObjectURL(file); + const link = document.createElement("a"); + link.href = url; + link.download = "project details.xlsx"; + document.body.appendChild(link); + link.click(); + }, + }); + } + }); + } + }); + }); + + + $("#archiveProject").click(function (e) { + e.preventDefault(); + var languageCode = null; + getCurrentLanguageCode(function (code) { + languageCode = code; + var confirmMessage = archiveMessagesSelected[languageCode]; + var textMessage = norowMessagesSelected[languageCode]; + var checkedRows = $(".all-project-row").filter(":checked"); + if (checkedRows.length === 0) { + Swal.fire({ + text: textMessage, + icon: "warning", + confirmButtonText: "Close", + }); + } else { + Swal.fire({ + text: confirmMessage, + icon: "info", + showCancelButton: true, + confirmButtonColor: "#008000", + cancelButtonColor: "#d33", + confirmButtonText: "Confirm", + }).then(function (result) { + if (result.isConfirmed) { + e.preventDefault(); + ids = []; + checkedRows.each(function () { + ids.push($(this).attr("id")); + }); + + $.ajax({ + type: "POST", + url: "/project/project-bulk-archive?is_active=False", + data: { + csrfmiddlewaretoken: getCookie("csrftoken"), + ids: JSON.stringify(ids), + }, + success: function (response, textStatus, jqXHR) { + if (jqXHR.status === 200) { + location.reload(); // Reload the current page + } else { + // console.log("Unexpected HTTP status:", jqXHR.status); + } + }, + }); + } + }); + } + }); + }); + + + $(document).on('click', '#archiveProject', function (e) { + e.preventDefault(); + var languageCode = null; + getCurrentLanguageCode(function (code) { + languageCode = code; + var confirmMessage = archiveMessagesSelected[languageCode]; + var textMessage = norowMessagesSelected[languageCode]; + ids = []; + ids.push($("#selectedInstances").attr("data-ids")); + ids = JSON.parse($("#selectedInstances").attr("data-ids")); + if (ids.length === 0) { + Swal.fire({ + text: textMessage, + icon: "warning", + confirmButtonText: "Close", + }); + } else { + Swal.fire({ + text: confirmMessage, + icon: "info", + showCancelButton: true, + confirmButtonColor: "#008000", + cancelButtonColor: "#d33", + confirmButtonText: "Confirm", + }).then(function (result) { + if (result.isConfirmed) { + // e.preventDefault(); + // ids = []; + // checkedRows.each(function () { + // ids.push($(this).attr("id")); + // }); + + $.ajax({ + type: "POST", + url: "/project/project-bulk-archive?is_active=False", + data: { + csrfmiddlewaretoken: getCookie("csrftoken"), + ids: JSON.stringify(ids), + }, + success: function (response, textStatus, jqXHR) { + if (jqXHR.status === 200) { + location.reload(); // Reload the current page + } else { + // console.log("Unexpected HTTP status:", jqXHR.status); + } + }, + }); + } + }); + } + }); + }); + + +$("#unArchiveProject").click(function (e) { + e.preventDefault(); + var languageCode = null; + getCurrentLanguageCode(function (code) { + languageCode = code; + var confirmMessage = unarchiveMessagesSelected[languageCode]; + var textMessage = norowMessagesSelected[languageCode]; + var checkedRows = $(".all-project-row").filter(":checked"); + if (checkedRows.length === 0) { + Swal.fire({ + text: textMessage, + icon: "warning", + confirmButtonText: "Close", + }); + } else { + Swal.fire({ + text: confirmMessage, + icon: "info", + showCancelButton: true, + confirmButtonColor: "#008000", + cancelButtonColor: "#d33", + confirmButtonText: "Confirm", + }).then(function (result) { + if (result.isConfirmed) { + var checkedRows = $(".all-project-row").filter(":checked"); + ids = []; + checkedRows.each(function () { + ids.push($(this).attr("id")); + }); + + $.ajax({ + type: "POST", + url: "/project/project-bulk-archive?is_active=True", + data: { + csrfmiddlewaretoken: getCookie("csrftoken"), + ids: JSON.stringify(ids), + }, + success: function (response, textStatus, jqXHR) { + if (jqXHR.status === 200) { + location.reload(); // Reload the current page + } else { + // console.log("Unexpected HTTP status:", jqXHR.status); + } + }, + }); + } + }); + } + }); + }); + + $(document).on('click', '#unArchiveProject', function (e) { + e.preventDefault(); + var languageCode = null; + getCurrentLanguageCode(function (code) { + languageCode = code; + var confirmMessage = unarchiveMessagesSelected[languageCode]; + var textMessage = norowMessagesSelected[languageCode]; + ids = []; + ids.push($("#selectedInstances").attr("data-ids")); + ids = JSON.parse($("#selectedInstances").attr("data-ids")); + if (ids.length === 0) { + Swal.fire({ + text: textMessage, + icon: "warning", + confirmButtonText: "Close", + }); + } else { + Swal.fire({ + text: confirmMessage, + icon: "info", + showCancelButton: true, + confirmButtonColor: "#008000", + cancelButtonColor: "#d33", + confirmButtonText: "Confirm", + }).then(function (result) { + if (result.isConfirmed) { + // var checkedRows = $(".all-project-row").filter(":checked"); + // ids = []; + // checkedRows.each(function () { + // ids.push($(this).attr("id")); + // }); + + $.ajax({ + type: "POST", + url: "/project/project-bulk-archive?is_active=True", + data: { + csrfmiddlewaretoken: getCookie("csrftoken"), + ids: JSON.stringify(ids), + }, + success: function (response, textStatus, jqXHR) { + if (jqXHR.status === 200) { + location.reload(); // Reload the current page + } else { + // console.log("Unexpected HTTP status:", jqXHR.status); + } + }, + }); + } + }); + } + }); + }); + +$("#deleteProject").click(function (e) { + e.preventDefault(); + var languageCode = null; + getCurrentLanguageCode(function (code) { + languageCode = code; + var confirmMessage = deleteMessage[languageCode]; + var textMessage = norowMessagesSelected[languageCode]; + var checkedRows = $(".all-project-row").filter(":checked"); + if (checkedRows.length === 0) { + Swal.fire({ + text: textMessage, + icon: "warning", + confirmButtonText: "Close", + }); + } else { + Swal.fire({ + text: confirmMessage, + icon: "error", + showCancelButton: true, + confirmButtonColor: "#008000", + cancelButtonColor: "#d33", + confirmButtonText: "Confirm", + }).then(function (result) { + if (result.isConfirmed) { + var checkedRows = $(".all-project-row").filter(":checked"); + ids = []; + checkedRows.each(function () { + ids.push($(this).attr("id")); + }); + + $.ajax({ + type: "POST", + url: "/project/project-bulk-delete", + data: { + csrfmiddlewaretoken: getCookie("csrftoken"), + ids: JSON.stringify(ids), + }, + success: function (response, textStatus, jqXHR) { + if (jqXHR.status === 200) { + location.reload(); // Reload the current page + } else { + // console.log("Unexpected HTTP status:", jqXHR.status); + } + }, + }); + } + }); + } + }); + }); + + + $(document).on('click', '#deleteProject', function (e) { + e.preventDefault(); + var languageCode = null; + getCurrentLanguageCode(function (code) { + languageCode = code; + var confirmMessage = deleteMessage[languageCode]; + var textMessage = norowMessagesSelected[languageCode]; + ids = []; + ids.push($("#selectedInstances").attr("data-ids")); + ids = JSON.parse($("#selectedInstances").attr("data-ids")); + if (ids.length === 0) { + Swal.fire({ + text: textMessage, + icon: "warning", + confirmButtonText: "Close", + }); + } else { + Swal.fire({ + text: confirmMessage, + icon: "error", + showCancelButton: true, + confirmButtonColor: "#008000", + cancelButtonColor: "#d33", + confirmButtonText: "Confirm", + }).then(function (result) { + if (result.isConfirmed) { + // var checkedRows = $(".all-project-row").filter(":checked"); + // ids = []; + // checkedRows.each(function () { + // ids.push($(this).attr("id")); + // }); + + $.ajax({ + type: "POST", + url: "/project/project-bulk-delete", + data: { + csrfmiddlewaretoken: getCookie("csrftoken"), + ids: JSON.stringify(ids), + }, + success: function (response, textStatus, jqXHR) { + if (jqXHR.status === 200) { + location.reload(); // Reload the current page + } else { + // console.log("Unexpected HTTP status:", jqXHR.status); + } + }, + }); + } + }); + } + }); }); diff --git a/project/static/project/project_view.js b/project/static/project/project_view.js index 4db7430a8..e29dcacdc 100644 --- a/project/static/project/project_view.js +++ b/project/static/project/project_view.js @@ -1,25 +1,25 @@ -$(document).ready(function(){ - $("#filter-project").keyup(function (e) { - $(".project-view-type").attr("hx-vals", `{"search":"${$(this).val()}"}`); - }); - $(".project-view-type").click(function (e) { - let view = $(this).data("view"); - var currentURL = window.location.href; - if (view != undefined){ - // Check if the query string already exists in the URL - if (/\?view=[^&]+/.test(currentURL)) { - // If the query parameter ?view exists, replace it with the new value - newURL = currentURL.replace(/\?view=[^&]+/, "?view="+view); - } - else { - // If the query parameter ?view does not exist, add it to the URL - var separator = currentURL.includes('?') ? '&' : '?'; - newURL = currentURL + separator + "view="+view; - } - - history.pushState({}, "", newURL); - $("#filter-project").attr("hx-vals", `{"view":"${view}"}`); - $('#timesheetForm').attr("hx-vals", `{"view":"${view}"}`); - } - }); +$(document).ready(function(){ + $("#filter-project").keyup(function (e) { + $(".project-view-type").attr("hx-vals", `{"search":"${$(this).val()}"}`); + }); + $(".project-view-type").click(function (e) { + let view = $(this).data("view"); + var currentURL = window.location.href; + if (view != undefined){ + // Check if the query string already exists in the URL + if (/\?view=[^&]+/.test(currentURL)) { + // If the query parameter ?view exists, replace it with the new value + newURL = currentURL.replace(/\?view=[^&]+/, "?view="+view); + } + else { + // If the query parameter ?view does not exist, add it to the URL + var separator = currentURL.includes('?') ? '&' : '?'; + newURL = currentURL + separator + "view="+view; + } + + history.pushState({}, "", newURL); + $("#filter-project").attr("hx-vals", `{"view":"${view}"}`); + $('#timesheetForm').attr("hx-vals", `{"view":"${view}"}`); + } + }); }); diff --git a/project/static/project/task_pipeline.js b/project/static/project/task_pipeline.js index e6371d458..0f591058f 100644 --- a/project/static/project/task_pipeline.js +++ b/project/static/project/task_pipeline.js @@ -1,177 +1,177 @@ -function toggleDropdown(id) { - var element = document.getElementById('taskCreateForm' + id); - element.classList.toggle('d-none'); -} - -function updateStageClass(element) { - const parent = $(element).parent(); - const isCollapsed = parent.hasClass('oh-kanban__section'); - const stageId = parent.data('stage-id'); // Get the data-stage-id attribute value - const collapsedProjectStages = JSON.parse(localStorage.getItem('collapsedProjectStages')) || []; // Get the collapsed stages from localStorage or initialize an empty array - - - // Toggle between class states - parent.toggleClass('oh-kanban__section oh-kanban-group stage'); - parent.toggleClass('ml-2 stage ui-sortable-handle'); - - if (isCollapsed) { - setTimeout(() => { - parent.addClass('oh-kanban-card--collapsed stage'); - }, 100); - if (!collapsedProjectStages.includes(stageId)) { - collapsedProjectStages.push(stageId); - localStorage.setItem('collapsedProjectStages', JSON.stringify(collapsedProjectStages)); - } - } else { - parent.removeClass('oh-kanban-card--collapsed'); - const index = collapsedProjectStages.indexOf(stageId); - if (index > -1) { - collapsedProjectStages.splice(index, 1); // Remove the stageId from the array - localStorage.setItem('collapsedProjectStages', JSON.stringify(collapsedProjectStages)); // Update localStorage - } - } - - // Toggle task container visibility - parent.find('.task-container').toggleClass('d-none'); - parent.find('.oh-kanban__head-actions').first().toggleClass('d-none'); - -} - -function loadCollapsedProjectStages() { - // Retrieve collapsed project stages from local storage - let collapsedProjectStages = []; - const collapsedProjectStagesData = localStorage.getItem('collapsedProjectStages'); - if (collapsedProjectStagesData) { - try { - // Parse the JSON only if it's a valid string - collapsedProjectStages = JSON.parse(collapsedProjectStagesData); - } catch (error) { - console.error('Error parsing JSON from local storage:', error); - } - } - - // Iterate over collapsed project stages - $.each(collapsedProjectStages, function (index, stageId) { - const stageElement = $(`[data-stage-id='${stageId}']`); - if (stageElement.length) { - const groupHead = stageElement.find('.oh-kanban-group__head'); - if (groupHead.length) { - updateStageClass(groupHead[0]); - } - } - }); -} - -$(document).ready(function () { - let old_stage_seq = {}; // Define the old sequence of stages globally - - loadCollapsedProjectStages(); - - function getCookie(name) { - let cookieValue = null; - if (document.cookie && document.cookie !== "") { - const cookies = document.cookie.split(";"); - for (let i = 0; i < cookies.length; i++) { - const cookie = cookies[i].trim(); - // Does this cookie string begin with the name we want? - if (cookie.substring(0, name.length + 1) === name + "=") { - cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); - break; - } - } - } - return cookieValue; - } - - $('.task-container').sortable({ - // Enables sortable functionality for task containers, - // tracking drag-and-drop events and updating task sequences via AJAX. - connectWith: ".task-container", - start: function (event, ui) { - var $draggedCard = ui.item; - var $taskOldStage = $draggedCard.closest('.oh-kanban__section'); - taskOldStageId = $taskOldStage.data('stage-id'); // Store the task old stage ID - window.$oldStageTaskCount = $taskOldStage.find('.task-count') - }, - stop: function (event, ui) { - var $draggedCard = ui.item; - var $taskNewStage = $draggedCard.closest('.oh-kanban__section'); - var $newStageTaskCount = $taskNewStage.find('.task-count'); - var taskNewStageId = $taskNewStage.data('stage-id'); // Get the task new stage ID - var taskId = $draggedCard.data('task-id'); - - // Check if the task has moved to a new stage - if (taskNewStageId !== taskOldStageId) { - var new_stage_seq = {}; - var task_container = $(this).children(".task"); - task_container.each(function (i, obj) { - new_stage_seq[$(obj).data('task-id')] = i; - }); - - // Update the task counts in old stage by -1 - var oldCount = parseInt(window.$oldStageTaskCount.html()); - window.$oldStageTaskCount.html(oldCount - 1); - - // Increment the new stage task count by 1 - var newCount = parseInt($newStageTaskCount.html()); - $newStageTaskCount.html(newCount + 1); - - // Trigger AJAX if the task has changed stages - $.ajax({ - type: "post", - url: '/project/drag-and-drop-task', - data: { - csrfmiddlewaretoken: getCookie("csrftoken"), - updated_task_id: taskId, - updated_stage_id: taskNewStageId, - previous_task_id: taskId, - previous_stage_id: taskOldStageId, - sequence: JSON.stringify(new_stage_seq), - }, - success: function (response) { - if (response.change === true) { - $("#reloadMessagesButton").click(); - } - }, - }); - } - } - }); - - $('.stage').mousedown(function (e) { - // Capture old sequence of stages on mousedown - old_stage_seq = {}; - $('.stage').each(function (i, obj) { - old_stage_seq[$(obj).attr('data-stage-id')] = i; - }); - }); - - $('.stage').mouseup(function (e) { - //For stage position rearrange event - setTimeout(function () { - var new_stage_seq = {}; - $('.stage').each(function (i, obj) { - new_stage_seq[$(obj).attr('data-stage-id')] = i; - }); - - // Compare old_stage_seq with new_stage_seq to trigger the ajax request - if (JSON.stringify(old_stage_seq) !== JSON.stringify(new_stage_seq)) { - $.ajax({ - type: 'post', - url: '/project/drag-and-drop-stage', - data: { - csrfmiddlewaretoken: getCookie("csrftoken"), - sequence: JSON.stringify(new_stage_seq), - }, - success: function (response) { - if (response.change) { - if (response.change === true) { - $("#reloadMessagesButton").click(); - } - } - }, - }); - } - }, 100); - }); +function toggleDropdown(id) { + var element = document.getElementById('taskCreateForm' + id); + element.classList.toggle('d-none'); +} + +function updateStageClass(element) { + const parent = $(element).parent(); + const isCollapsed = parent.hasClass('oh-kanban__section'); + const stageId = parent.data('stage-id'); // Get the data-stage-id attribute value + const collapsedProjectStages = JSON.parse(localStorage.getItem('collapsedProjectStages')) || []; // Get the collapsed stages from localStorage or initialize an empty array + + + // Toggle between class states + parent.toggleClass('oh-kanban__section oh-kanban-group stage'); + parent.toggleClass('ml-2 stage ui-sortable-handle'); + + if (isCollapsed) { + setTimeout(() => { + parent.addClass('oh-kanban-card--collapsed stage'); + }, 100); + if (!collapsedProjectStages.includes(stageId)) { + collapsedProjectStages.push(stageId); + localStorage.setItem('collapsedProjectStages', JSON.stringify(collapsedProjectStages)); + } + } else { + parent.removeClass('oh-kanban-card--collapsed'); + const index = collapsedProjectStages.indexOf(stageId); + if (index > -1) { + collapsedProjectStages.splice(index, 1); // Remove the stageId from the array + localStorage.setItem('collapsedProjectStages', JSON.stringify(collapsedProjectStages)); // Update localStorage + } + } + + // Toggle task container visibility + parent.find('.task-container').toggleClass('d-none'); + parent.find('.oh-kanban__head-actions').first().toggleClass('d-none'); + +} + +function loadCollapsedProjectStages() { + // Retrieve collapsed project stages from local storage + let collapsedProjectStages = []; + const collapsedProjectStagesData = localStorage.getItem('collapsedProjectStages'); + if (collapsedProjectStagesData) { + try { + // Parse the JSON only if it's a valid string + collapsedProjectStages = JSON.parse(collapsedProjectStagesData); + } catch (error) { + console.error('Error parsing JSON from local storage:', error); + } + } + + // Iterate over collapsed project stages + $.each(collapsedProjectStages, function (index, stageId) { + const stageElement = $(`[data-stage-id='${stageId}']`); + if (stageElement.length) { + const groupHead = stageElement.find('.oh-kanban-group__head'); + if (groupHead.length) { + updateStageClass(groupHead[0]); + } + } + }); +} + +$(document).ready(function () { + let old_stage_seq = {}; // Define the old sequence of stages globally + + loadCollapsedProjectStages(); + + function getCookie(name) { + let cookieValue = null; + if (document.cookie && document.cookie !== "") { + const cookies = document.cookie.split(";"); + for (let i = 0; i < cookies.length; i++) { + const cookie = cookies[i].trim(); + // Does this cookie string begin with the name we want? + if (cookie.substring(0, name.length + 1) === name + "=") { + cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); + break; + } + } + } + return cookieValue; + } + + $('.task-container').sortable({ + // Enables sortable functionality for task containers, + // tracking drag-and-drop events and updating task sequences via AJAX. + connectWith: ".task-container", + start: function (event, ui) { + var $draggedCard = ui.item; + var $taskOldStage = $draggedCard.closest('.oh-kanban__section'); + taskOldStageId = $taskOldStage.data('stage-id'); // Store the task old stage ID + window.$oldStageTaskCount = $taskOldStage.find('.task-count') + }, + stop: function (event, ui) { + var $draggedCard = ui.item; + var $taskNewStage = $draggedCard.closest('.oh-kanban__section'); + var $newStageTaskCount = $taskNewStage.find('.task-count'); + var taskNewStageId = $taskNewStage.data('stage-id'); // Get the task new stage ID + var taskId = $draggedCard.data('task-id'); + + // Check if the task has moved to a new stage + if (taskNewStageId !== taskOldStageId) { + var new_stage_seq = {}; + var task_container = $(this).children(".task"); + task_container.each(function (i, obj) { + new_stage_seq[$(obj).data('task-id')] = i; + }); + + // Update the task counts in old stage by -1 + var oldCount = parseInt(window.$oldStageTaskCount.html()); + window.$oldStageTaskCount.html(oldCount - 1); + + // Increment the new stage task count by 1 + var newCount = parseInt($newStageTaskCount.html()); + $newStageTaskCount.html(newCount + 1); + + // Trigger AJAX if the task has changed stages + $.ajax({ + type: "post", + url: '/project/drag-and-drop-task', + data: { + csrfmiddlewaretoken: getCookie("csrftoken"), + updated_task_id: taskId, + updated_stage_id: taskNewStageId, + previous_task_id: taskId, + previous_stage_id: taskOldStageId, + sequence: JSON.stringify(new_stage_seq), + }, + success: function (response) { + if (response.change === true) { + $("#reloadMessagesButton").click(); + } + }, + }); + } + } + }); + + $('.stage').mousedown(function (e) { + // Capture old sequence of stages on mousedown + old_stage_seq = {}; + $('.stage').each(function (i, obj) { + old_stage_seq[$(obj).attr('data-stage-id')] = i; + }); + }); + + $('.stage').mouseup(function (e) { + //For stage position rearrange event + setTimeout(function () { + var new_stage_seq = {}; + $('.stage').each(function (i, obj) { + new_stage_seq[$(obj).attr('data-stage-id')] = i; + }); + + // Compare old_stage_seq with new_stage_seq to trigger the ajax request + if (JSON.stringify(old_stage_seq) !== JSON.stringify(new_stage_seq)) { + $.ajax({ + type: 'post', + url: '/project/drag-and-drop-stage', + data: { + csrfmiddlewaretoken: getCookie("csrftoken"), + sequence: JSON.stringify(new_stage_seq), + }, + success: function (response) { + if (response.change) { + if (response.change === true) { + $("#reloadMessagesButton").click(); + } + } + }, + }); + } + }, 100); + }); }); diff --git a/project/static/task_all/task_all_action.js b/project/static/task_all/task_all_action.js index 6bd7c7e0d..b470e5f98 100644 --- a/project/static/task_all/task_all_action.js +++ b/project/static/task_all/task_all_action.js @@ -1,371 +1,371 @@ -var archiveMessage = { - // ar: "هل ترغب حقًا في أرشفة جميع الموظفين المحددين؟", - // de: "Möchten Sie wirklich alle ausgewählten Mitarbeiter archivieren?", - // es: "¿Realmente quieres archivar a todos los empleados seleccionados?", - en: "Do you really want to archive all the selected tasks?", - // fr: "Voulez-vous vraiment archiver tous les employés sélectionnés ?", - }; - - var unarchiveMessage = { - // ar: "هل ترغب حقًا في إلغاء أرشفة جميع الموظفين المحددين؟", - // de: "Möchten Sie wirklich alle ausgewählten Mitarbeiter aus der Archivierung zurückholen?", - // es: "¿Realmente quieres desarchivar a todos los empleados seleccionados?", - en: "Do you really want to unarchive all the selected tasks?", - // fr: "Voulez-vous vraiment désarchiver tous les employés sélectionnés?", - }; - - var deleteMessage = { - // ar: "هل ترغب حقًا في حذف جميع الموظفين المحددين؟", - // de: "Möchten Sie wirklich alle ausgewählten Mitarbeiter löschen?", - // es: "¿Realmente quieres eliminar a todos los empleados seleccionados?", - en: "Do you really want to delete all the selected tasks?", - // fr: "Voulez-vous vraiment supprimer tous les employés sélectionnés?", - }; - - var norowMessage = { - // ar: "لم يتم تحديد أي صفوف.", - // de: "Es wurden keine Zeilen ausgewählt.", - // es: "No se han seleccionado filas.", - en: "No rows have been selected.", - // fr: "Aucune ligne n'a été sélectionnée.", - }; - - function getCookie(name) { - let cookieValue = null; - if (document.cookie && document.cookie !== "") { - const cookies = document.cookie.split(";"); - for (let i = 0; i < cookies.length; i++) { - const cookie = cookies[i].trim(); - // Does this cookie string begin with the name we want? - if (cookie.substring(0, name.length + 1) === name + "=") { - cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); - break; - } - } - } - return cookieValue; - } - - function getCurrentLanguageCode(callback) { - $.ajax({ - type: "GET", - url: "/employee/get-language-code/", - success: function (response) { - var languageCode = response.language_code; - callback(languageCode); // Pass the language code to the callback - }, - }); - } - $(".all-task-all").change(function (e) { - var is_checked = $(this).is(":checked"); - if (is_checked) { - $(".all-task-all-row").prop("checked", true); - } else { - $(".all-task-all-row").prop("checked", false); - } - }); - - $("#archiveTaskAll").click(function (e) { - e.preventDefault(); - var languageCode = null; - getCurrentLanguageCode(function (code) { - languageCode = code; - var confirmMessage = archiveMessage[languageCode]; - var textMessage = norowMessage[languageCode]; - var checkedRows = $(".all-task-all-row").filter(":checked"); - if (checkedRows.length === 0) { - Swal.fire({ - text: textMessage, - icon: "warning", - confirmButtonText: "Close", - }); - } else { - Swal.fire({ - text: confirmMessage, - icon: "info", - showCancelButton: true, - confirmButtonColor: "#008000", - cancelButtonColor: "#d33", - confirmButtonText: "Confirm", - }).then(function (result) { - if (result.isConfirmed) { - e.preventDefault(); - ids = []; - checkedRows.each(function () { - ids.push($(this).attr("id")); - }); - - $.ajax({ - type: "POST", - url: "/project/task-all-bulk-archive?is_active=False", - data: { - csrfmiddlewaretoken: getCookie("csrftoken"), - ids: JSON.stringify(ids), - }, - success: function (response, textStatus, jqXHR) { - if (jqXHR.status === 200) { - location.reload(); // Reload the current page - } else { - // console.log("Unexpected HTTP status:", jqXHR.status); - } - }, - }); - } - }); - } - }); - }); - -//Bulk archive - -$(document).on('click', '#archiveTask', function (e) { - e.preventDefault(); - var languageCode = null; - getCurrentLanguageCode(function (code) { - languageCode = code; - var confirmMessage = archiveMessage[languageCode]; - var textMessage = norowMessage[languageCode]; - ids = []; - ids.push($("#selectedInstances").attr("data-ids")); - ids = JSON.parse($("#selectedInstances").attr("data-ids")); - if (ids.length === 0) { - Swal.fire({ - text: textMessage, - icon: "warning", - confirmButtonText: "Close", - }); - } else { - Swal.fire({ - text: confirmMessage, - icon: "info", - showCancelButton: true, - confirmButtonColor: "#008000", - cancelButtonColor: "#d33", - confirmButtonText: "Confirm", - }).then(function (result) { - if (result.isConfirmed) { - - $.ajax({ - type: "POST", - url: "/project/task-all-bulk-archive?is_active=False", - data: { - csrfmiddlewaretoken: getCookie("csrftoken"), - ids: JSON.stringify(ids), - }, - success: function (response, textStatus, jqXHR) { - if (jqXHR.status === 200) { - location.reload(); - } else { - - } - }, - }); - } - }); - } - }); -}); - - - -$("#unArchiveTaskAll").click(function (e) { - e.preventDefault(); - var languageCode = null; - getCurrentLanguageCode(function (code) { - languageCode = code; - var confirmMessage = unarchiveMessage[languageCode]; - var textMessage = norowMessage[languageCode]; - var checkedRows = $(".all-task-all-row").filter(":checked"); - if (checkedRows.length === 0) { - Swal.fire({ - text: textMessage, - icon: "warning", - confirmButtonText: "Close", - }); - } else { - Swal.fire({ - text: confirmMessage, - icon: "info", - showCancelButton: true, - confirmButtonColor: "#008000", - cancelButtonColor: "#d33", - confirmButtonText: "Confirm", - }).then(function (result) { - if (result.isConfirmed) { - var checkedRows = $(".all-task-all-row").filter(":checked"); - ids = []; - checkedRows.each(function () { - ids.push($(this).attr("id")); - }); - - $.ajax({ - type: "POST", - url: "/project/task-all-bulk-archive?is_active=True", - data: { - csrfmiddlewaretoken: getCookie("csrftoken"), - ids: JSON.stringify(ids), - }, - success: function (response, textStatus, jqXHR) { - if (jqXHR.status === 200) { - location.reload(); // Reload the current page - } else { - // console.log("Unexpected HTTP status:", jqXHR.status); - } - }, - }); - } - }); - } - }); - }); - -//Bulk unarchive - -$(document).on('click', '#unArchiveTask', function (e) { - e.preventDefault(); - var languageCode = null; - getCurrentLanguageCode(function (code) { - languageCode = code; - var confirmMessage = unarchiveMessage[languageCode]; - var textMessage = norowMessage[languageCode]; - ids = []; - ids.push($("#selectedInstances").attr("data-ids")); - ids = JSON.parse($("#selectedInstances").attr("data-ids")); - if (ids.length === 0) { - Swal.fire({ - text: textMessage, - icon: "warning", - confirmButtonText: "Close", - }); - } else { - Swal.fire({ - text: confirmMessage, - icon: "info", - showCancelButton: true, - confirmButtonColor: "#008000", - cancelButtonColor: "#d33", - confirmButtonText: "Confirm", - }).then(function (result) { - if (result.isConfirmed) { - - $.ajax({ - type: "POST", - url: "/project/task-all-bulk-archive?is_active=True", - data: { - csrfmiddlewaretoken: getCookie("csrftoken"), - ids: JSON.stringify(ids), - }, - success: function (response, textStatus, jqXHR) { - if (jqXHR.status === 200) { - location.reload(); - } else { - - } - }, - }); - } - }); - } - }); -}); - -$("#deleteTaskAll").click(function (e) { - e.preventDefault(); - var languageCode = null; - getCurrentLanguageCode(function (code) { - languageCode = code; - var confirmMessage = deleteMessage[languageCode]; - var textMessage = norowMessage[languageCode]; - var checkedRows = $(".all-task-all-row").filter(":checked"); - if (checkedRows.length === 0) { - Swal.fire({ - text: textMessage, - icon: "warning", - confirmButtonText: "Close", - }); - } else { - Swal.fire({ - text: confirmMessage, - icon: "error", - showCancelButton: true, - confirmButtonColor: "#008000", - cancelButtonColor: "#d33", - confirmButtonText: "Confirm", - }).then(function (result) { - if (result.isConfirmed) { - var checkedRows = $(".all-task-all-row").filter(":checked"); - ids = []; - checkedRows.each(function () { - ids.push($(this).attr("id")); - }); - - $.ajax({ - type: "POST", - url: "/project/task-all-bulk-delete", - data: { - csrfmiddlewaretoken: getCookie("csrftoken"), - ids: JSON.stringify(ids), - }, - success: function (response, textStatus, jqXHR) { - if (jqXHR.status === 200) { - location.reload(); // Reload the current page - } else { - // console.log("Unexpected HTTP status:", jqXHR.status); - } - }, - }); - } - }); - } - }); - }); - -//Bulk delete - -$(document).on('click', '#deleteTask', function (e) { - e.preventDefault(); - var languageCode = null; - getCurrentLanguageCode(function (code) { - languageCode = code; - var confirmMessage = deleteMessage[languageCode]; - var textMessage = norowMessage[languageCode]; - ids = []; - ids.push($("#selectedInstances").attr("data-ids")); - ids = JSON.parse($("#selectedInstances").attr("data-ids")); - if (ids.length === 0) { - Swal.fire({ - text: textMessage, - icon: "warning", - confirmButtonText: "Close", - }); - } else { - Swal.fire({ - text: confirmMessage, - icon: "info", - showCancelButton: true, - confirmButtonColor: "#008000", - cancelButtonColor: "#d33", - confirmButtonText: "Confirm", - }).then(function (result) { - if (result.isConfirmed) { - - $.ajax({ - type: "POST", - url: "/project/task-all-bulk-delete", - data: { - csrfmiddlewaretoken: getCookie("csrftoken"), - ids: JSON.stringify(ids), - }, - success: function (response, textStatus, jqXHR) { - if (jqXHR.status === 200) { - location.reload(); - } else { - - } - }, - }); - } - }); - } - }); +var archiveMessage = { + // ar: "هل ترغب حقًا في أرشفة جميع الموظفين المحددين؟", + // de: "Möchten Sie wirklich alle ausgewählten Mitarbeiter archivieren?", + // es: "¿Realmente quieres archivar a todos los empleados seleccionados?", + en: "Do you really want to archive all the selected tasks?", + // fr: "Voulez-vous vraiment archiver tous les employés sélectionnés ?", + }; + + var unarchiveMessage = { + // ar: "هل ترغب حقًا في إلغاء أرشفة جميع الموظفين المحددين؟", + // de: "Möchten Sie wirklich alle ausgewählten Mitarbeiter aus der Archivierung zurückholen?", + // es: "¿Realmente quieres desarchivar a todos los empleados seleccionados?", + en: "Do you really want to unarchive all the selected tasks?", + // fr: "Voulez-vous vraiment désarchiver tous les employés sélectionnés?", + }; + + var deleteMessage = { + // ar: "هل ترغب حقًا في حذف جميع الموظفين المحددين؟", + // de: "Möchten Sie wirklich alle ausgewählten Mitarbeiter löschen?", + // es: "¿Realmente quieres eliminar a todos los empleados seleccionados?", + en: "Do you really want to delete all the selected tasks?", + // fr: "Voulez-vous vraiment supprimer tous les employés sélectionnés?", + }; + + var norowMessage = { + // ar: "لم يتم تحديد أي صفوف.", + // de: "Es wurden keine Zeilen ausgewählt.", + // es: "No se han seleccionado filas.", + en: "No rows have been selected.", + // fr: "Aucune ligne n'a été sélectionnée.", + }; + + function getCookie(name) { + let cookieValue = null; + if (document.cookie && document.cookie !== "") { + const cookies = document.cookie.split(";"); + for (let i = 0; i < cookies.length; i++) { + const cookie = cookies[i].trim(); + // Does this cookie string begin with the name we want? + if (cookie.substring(0, name.length + 1) === name + "=") { + cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); + break; + } + } + } + return cookieValue; + } + + function getCurrentLanguageCode(callback) { + $.ajax({ + type: "GET", + url: "/employee/get-language-code/", + success: function (response) { + var languageCode = response.language_code; + callback(languageCode); // Pass the language code to the callback + }, + }); + } + $(".all-task-all").change(function (e) { + var is_checked = $(this).is(":checked"); + if (is_checked) { + $(".all-task-all-row").prop("checked", true); + } else { + $(".all-task-all-row").prop("checked", false); + } + }); + + $("#archiveTaskAll").click(function (e) { + e.preventDefault(); + var languageCode = null; + getCurrentLanguageCode(function (code) { + languageCode = code; + var confirmMessage = archiveMessage[languageCode]; + var textMessage = norowMessage[languageCode]; + var checkedRows = $(".all-task-all-row").filter(":checked"); + if (checkedRows.length === 0) { + Swal.fire({ + text: textMessage, + icon: "warning", + confirmButtonText: "Close", + }); + } else { + Swal.fire({ + text: confirmMessage, + icon: "info", + showCancelButton: true, + confirmButtonColor: "#008000", + cancelButtonColor: "#d33", + confirmButtonText: "Confirm", + }).then(function (result) { + if (result.isConfirmed) { + e.preventDefault(); + ids = []; + checkedRows.each(function () { + ids.push($(this).attr("id")); + }); + + $.ajax({ + type: "POST", + url: "/project/task-all-bulk-archive?is_active=False", + data: { + csrfmiddlewaretoken: getCookie("csrftoken"), + ids: JSON.stringify(ids), + }, + success: function (response, textStatus, jqXHR) { + if (jqXHR.status === 200) { + location.reload(); // Reload the current page + } else { + // console.log("Unexpected HTTP status:", jqXHR.status); + } + }, + }); + } + }); + } + }); + }); + +//Bulk archive + +$(document).on('click', '#archiveTask', function (e) { + e.preventDefault(); + var languageCode = null; + getCurrentLanguageCode(function (code) { + languageCode = code; + var confirmMessage = archiveMessage[languageCode]; + var textMessage = norowMessage[languageCode]; + ids = []; + ids.push($("#selectedInstances").attr("data-ids")); + ids = JSON.parse($("#selectedInstances").attr("data-ids")); + if (ids.length === 0) { + Swal.fire({ + text: textMessage, + icon: "warning", + confirmButtonText: "Close", + }); + } else { + Swal.fire({ + text: confirmMessage, + icon: "info", + showCancelButton: true, + confirmButtonColor: "#008000", + cancelButtonColor: "#d33", + confirmButtonText: "Confirm", + }).then(function (result) { + if (result.isConfirmed) { + + $.ajax({ + type: "POST", + url: "/project/task-all-bulk-archive?is_active=False", + data: { + csrfmiddlewaretoken: getCookie("csrftoken"), + ids: JSON.stringify(ids), + }, + success: function (response, textStatus, jqXHR) { + if (jqXHR.status === 200) { + location.reload(); + } else { + + } + }, + }); + } + }); + } + }); +}); + + + +$("#unArchiveTaskAll").click(function (e) { + e.preventDefault(); + var languageCode = null; + getCurrentLanguageCode(function (code) { + languageCode = code; + var confirmMessage = unarchiveMessage[languageCode]; + var textMessage = norowMessage[languageCode]; + var checkedRows = $(".all-task-all-row").filter(":checked"); + if (checkedRows.length === 0) { + Swal.fire({ + text: textMessage, + icon: "warning", + confirmButtonText: "Close", + }); + } else { + Swal.fire({ + text: confirmMessage, + icon: "info", + showCancelButton: true, + confirmButtonColor: "#008000", + cancelButtonColor: "#d33", + confirmButtonText: "Confirm", + }).then(function (result) { + if (result.isConfirmed) { + var checkedRows = $(".all-task-all-row").filter(":checked"); + ids = []; + checkedRows.each(function () { + ids.push($(this).attr("id")); + }); + + $.ajax({ + type: "POST", + url: "/project/task-all-bulk-archive?is_active=True", + data: { + csrfmiddlewaretoken: getCookie("csrftoken"), + ids: JSON.stringify(ids), + }, + success: function (response, textStatus, jqXHR) { + if (jqXHR.status === 200) { + location.reload(); // Reload the current page + } else { + // console.log("Unexpected HTTP status:", jqXHR.status); + } + }, + }); + } + }); + } + }); + }); + +//Bulk unarchive + +$(document).on('click', '#unArchiveTask', function (e) { + e.preventDefault(); + var languageCode = null; + getCurrentLanguageCode(function (code) { + languageCode = code; + var confirmMessage = unarchiveMessage[languageCode]; + var textMessage = norowMessage[languageCode]; + ids = []; + ids.push($("#selectedInstances").attr("data-ids")); + ids = JSON.parse($("#selectedInstances").attr("data-ids")); + if (ids.length === 0) { + Swal.fire({ + text: textMessage, + icon: "warning", + confirmButtonText: "Close", + }); + } else { + Swal.fire({ + text: confirmMessage, + icon: "info", + showCancelButton: true, + confirmButtonColor: "#008000", + cancelButtonColor: "#d33", + confirmButtonText: "Confirm", + }).then(function (result) { + if (result.isConfirmed) { + + $.ajax({ + type: "POST", + url: "/project/task-all-bulk-archive?is_active=True", + data: { + csrfmiddlewaretoken: getCookie("csrftoken"), + ids: JSON.stringify(ids), + }, + success: function (response, textStatus, jqXHR) { + if (jqXHR.status === 200) { + location.reload(); + } else { + + } + }, + }); + } + }); + } + }); +}); + +$("#deleteTaskAll").click(function (e) { + e.preventDefault(); + var languageCode = null; + getCurrentLanguageCode(function (code) { + languageCode = code; + var confirmMessage = deleteMessage[languageCode]; + var textMessage = norowMessage[languageCode]; + var checkedRows = $(".all-task-all-row").filter(":checked"); + if (checkedRows.length === 0) { + Swal.fire({ + text: textMessage, + icon: "warning", + confirmButtonText: "Close", + }); + } else { + Swal.fire({ + text: confirmMessage, + icon: "error", + showCancelButton: true, + confirmButtonColor: "#008000", + cancelButtonColor: "#d33", + confirmButtonText: "Confirm", + }).then(function (result) { + if (result.isConfirmed) { + var checkedRows = $(".all-task-all-row").filter(":checked"); + ids = []; + checkedRows.each(function () { + ids.push($(this).attr("id")); + }); + + $.ajax({ + type: "POST", + url: "/project/task-all-bulk-delete", + data: { + csrfmiddlewaretoken: getCookie("csrftoken"), + ids: JSON.stringify(ids), + }, + success: function (response, textStatus, jqXHR) { + if (jqXHR.status === 200) { + location.reload(); // Reload the current page + } else { + // console.log("Unexpected HTTP status:", jqXHR.status); + } + }, + }); + } + }); + } + }); + }); + +//Bulk delete + +$(document).on('click', '#deleteTask', function (e) { + e.preventDefault(); + var languageCode = null; + getCurrentLanguageCode(function (code) { + languageCode = code; + var confirmMessage = deleteMessage[languageCode]; + var textMessage = norowMessage[languageCode]; + ids = []; + ids.push($("#selectedInstances").attr("data-ids")); + ids = JSON.parse($("#selectedInstances").attr("data-ids")); + if (ids.length === 0) { + Swal.fire({ + text: textMessage, + icon: "warning", + confirmButtonText: "Close", + }); + } else { + Swal.fire({ + text: confirmMessage, + icon: "info", + showCancelButton: true, + confirmButtonColor: "#008000", + cancelButtonColor: "#d33", + confirmButtonText: "Confirm", + }).then(function (result) { + if (result.isConfirmed) { + + $.ajax({ + type: "POST", + url: "/project/task-all-bulk-delete", + data: { + csrfmiddlewaretoken: getCookie("csrftoken"), + ids: JSON.stringify(ids), + }, + success: function (response, textStatus, jqXHR) { + if (jqXHR.status === 200) { + location.reload(); + } else { + + } + }, + }); + } + }); + } + }); }); diff --git a/project/static/time_sheet/time_sheet_action.js b/project/static/time_sheet/time_sheet_action.js index b8b0ddd87..f0c9f9e1f 100644 --- a/project/static/time_sheet/time_sheet_action.js +++ b/project/static/time_sheet/time_sheet_action.js @@ -1,172 +1,172 @@ - -var archiveMessages = { - // ar: "هل ترغب حقًا في أرشفة جميع الموظفين المحددين؟", - // de: "Möchten Sie wirklich alle ausgewählten Mitarbeiter archivieren?", - // es: "¿Realmente quieres archivar a todos los empleados seleccionados?", - en: "Do you really want to archive all the selected timesheet?", - // fr: "Voulez-vous vraiment archiver tous les employés sélectionnés ?", - }; - - var unarchiveMessages = { - // ar: "هل ترغب حقًا في إلغاء أرشفة جميع الموظفين المحددين؟", - // de: "Möchten Sie wirklich alle ausgewählten Mitarbeiter aus der Archivierung zurückholen?", - // es: "¿Realmente quieres desarchivar a todos los empleados seleccionados?", - en: "Do you really want to unarchive all the selected timesheet?", - // fr: "Voulez-vous vraiment désarchiver tous les employés sélectionnés?", - }; - - var deleteMessagesBulk = { - // ar: "هل ترغب حقًا في حذف جميع الموظفين المحددين؟", - // de: "Möchten Sie wirklich alle ausgewählten Mitarbeiter löschen?", - // es: "¿Realmente quieres eliminar a todos los empleados seleccionados?", - en: "Do you really want to delete all the selected timesheet?", - // fr: "Voulez-vous vraiment supprimer tous les employés sélectionnés?", - }; - - var norowMessages = { - // ar: "لم يتم تحديد أي صفوف.", - // de: "Es wurden keine Zeilen ausgewählt.", - // es: "No se han seleccionado filas.", - en: "No rows have been selected.", - // fr: "Aucune ligne n'a été sélectionnée.", - }; - - function getCookie(name) { - let cookieValue = null; - if (document.cookie && document.cookie !== "") { - const cookies = document.cookie.split(";"); - for (let i = 0; i < cookies.length; i++) { - const cookie = cookies[i].trim(); - // Does this cookie string begin with the name we want? - if (cookie.substring(0, name.length + 1) === name + "=") { - cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); - break; - } - } - } - return cookieValue; - } - - function getCurrentLanguageCode(callback) { - $.ajax({ - type: "GET", - url: "/employee/get-language-code/", - success: function (response) { - var languageCode = response.language_code; - callback(languageCode); // Pass the language code to the callback - }, - }); - } - $(".all-time-sheet").change(function (e) { - var is_checked = $(this).is(":checked"); - if (is_checked) { - $(".all-time-sheet-row").prop("checked", true); - } else { - $(".all-time-sheet-row").prop("checked", false); - } - }); - - -$("#deleteTimeSheet").click(function (e) { - e.preventDefault(); - var languageCode = null; - getCurrentLanguageCode(function (code) { - languageCode = code; - var confirmMessage = deleteMessagesBulk[languageCode]; - var textMessage = norowMessages[languageCode]; - var checkedRows = $(".all-time-sheet-row").filter(":checked"); - if (checkedRows.length === 0) { - Swal.fire({ - text: textMessage, - icon: "warning", - confirmButtonText: "Close", - }); - } else { - Swal.fire({ - text: confirmMessage, - icon: "error", - showCancelButton: true, - confirmButtonColor: "#008000", - cancelButtonColor: "#d33", - confirmButtonText: "Confirm", - }).then(function (result) { - if (result.isConfirmed) { - var checkedRows = $(".all-time-sheet-row").filter(":checked"); - ids = []; - checkedRows.each(function () { - ids.push($(this).attr("id")); - }); - - $.ajax({ - type: "POST", - url: "/project/time-sheet-bulk-delete", - data: { - csrfmiddlewaretoken: getCookie("csrftoken"), - ids: JSON.stringify(ids), - }, - success: function (response, textStatus, jqXHR) { - if (jqXHR.status === 200) { - location.reload(); // Reload the current page - } else { - // console.log("Unexpected HTTP status:", jqXHR.status); - } - }, - }); - } - }); - } - }); - }); - - - function deleteTimeSheet(){ - var languageCode = null; - getCurrentLanguageCode(function (code) { - languageCode = code; - var confirmMessage = deleteMessagesBulk[languageCode]; - var textMessage = norowMessages[languageCode]; - ids = []; - ids.push($("#selectedInstances").attr("data-ids")); - ids = JSON.parse($("#selectedInstances").attr("data-ids")); - if (ids.length === 0) { - Swal.fire({ - text: textMessage, - icon: "warning", - confirmButtonText: "Close", - }); - } else { - Swal.fire({ - text: confirmMessage, - icon: "error", - showCancelButton: true, - confirmButtonColor: "#008000", - cancelButtonColor: "#d33", - confirmButtonText: "Confirm", - }).then(function (result) { - if (result.isConfirmed) { - // var checkedRows = $(".all-time-sheet-row").filter(":checked"); - // ids = []; - // checkedRows.each(function () { - // ids.push($(this).attr("id")); - // }); - - $.ajax({ - type: "POST", - url: "/project/time-sheet-bulk-delete", - data: { - csrfmiddlewaretoken: getCookie("csrftoken"), - ids: JSON.stringify(ids), - }, - success: function (response, textStatus, jqXHR) { - if (jqXHR.status === 200) { - location.reload(); // Reload the current page - } else { - // console.log("Unexpected HTTP status:", jqXHR.status); - } - }, - }); - } - }); - } - }); + +var archiveMessages = { + // ar: "هل ترغب حقًا في أرشفة جميع الموظفين المحددين؟", + // de: "Möchten Sie wirklich alle ausgewählten Mitarbeiter archivieren?", + // es: "¿Realmente quieres archivar a todos los empleados seleccionados?", + en: "Do you really want to archive all the selected timesheet?", + // fr: "Voulez-vous vraiment archiver tous les employés sélectionnés ?", + }; + + var unarchiveMessages = { + // ar: "هل ترغب حقًا في إلغاء أرشفة جميع الموظفين المحددين؟", + // de: "Möchten Sie wirklich alle ausgewählten Mitarbeiter aus der Archivierung zurückholen?", + // es: "¿Realmente quieres desarchivar a todos los empleados seleccionados?", + en: "Do you really want to unarchive all the selected timesheet?", + // fr: "Voulez-vous vraiment désarchiver tous les employés sélectionnés?", + }; + + var deleteMessagesBulk = { + // ar: "هل ترغب حقًا في حذف جميع الموظفين المحددين؟", + // de: "Möchten Sie wirklich alle ausgewählten Mitarbeiter löschen?", + // es: "¿Realmente quieres eliminar a todos los empleados seleccionados?", + en: "Do you really want to delete all the selected timesheet?", + // fr: "Voulez-vous vraiment supprimer tous les employés sélectionnés?", + }; + + var norowMessages = { + // ar: "لم يتم تحديد أي صفوف.", + // de: "Es wurden keine Zeilen ausgewählt.", + // es: "No se han seleccionado filas.", + en: "No rows have been selected.", + // fr: "Aucune ligne n'a été sélectionnée.", + }; + + function getCookie(name) { + let cookieValue = null; + if (document.cookie && document.cookie !== "") { + const cookies = document.cookie.split(";"); + for (let i = 0; i < cookies.length; i++) { + const cookie = cookies[i].trim(); + // Does this cookie string begin with the name we want? + if (cookie.substring(0, name.length + 1) === name + "=") { + cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); + break; + } + } + } + return cookieValue; + } + + function getCurrentLanguageCode(callback) { + $.ajax({ + type: "GET", + url: "/employee/get-language-code/", + success: function (response) { + var languageCode = response.language_code; + callback(languageCode); // Pass the language code to the callback + }, + }); + } + $(".all-time-sheet").change(function (e) { + var is_checked = $(this).is(":checked"); + if (is_checked) { + $(".all-time-sheet-row").prop("checked", true); + } else { + $(".all-time-sheet-row").prop("checked", false); + } + }); + + +$("#deleteTimeSheet").click(function (e) { + e.preventDefault(); + var languageCode = null; + getCurrentLanguageCode(function (code) { + languageCode = code; + var confirmMessage = deleteMessagesBulk[languageCode]; + var textMessage = norowMessages[languageCode]; + var checkedRows = $(".all-time-sheet-row").filter(":checked"); + if (checkedRows.length === 0) { + Swal.fire({ + text: textMessage, + icon: "warning", + confirmButtonText: "Close", + }); + } else { + Swal.fire({ + text: confirmMessage, + icon: "error", + showCancelButton: true, + confirmButtonColor: "#008000", + cancelButtonColor: "#d33", + confirmButtonText: "Confirm", + }).then(function (result) { + if (result.isConfirmed) { + var checkedRows = $(".all-time-sheet-row").filter(":checked"); + ids = []; + checkedRows.each(function () { + ids.push($(this).attr("id")); + }); + + $.ajax({ + type: "POST", + url: "/project/time-sheet-bulk-delete", + data: { + csrfmiddlewaretoken: getCookie("csrftoken"), + ids: JSON.stringify(ids), + }, + success: function (response, textStatus, jqXHR) { + if (jqXHR.status === 200) { + location.reload(); // Reload the current page + } else { + // console.log("Unexpected HTTP status:", jqXHR.status); + } + }, + }); + } + }); + } + }); + }); + + + function deleteTimeSheet(){ + var languageCode = null; + getCurrentLanguageCode(function (code) { + languageCode = code; + var confirmMessage = deleteMessagesBulk[languageCode]; + var textMessage = norowMessages[languageCode]; + ids = []; + ids.push($("#selectedInstances").attr("data-ids")); + ids = JSON.parse($("#selectedInstances").attr("data-ids")); + if (ids.length === 0) { + Swal.fire({ + text: textMessage, + icon: "warning", + confirmButtonText: "Close", + }); + } else { + Swal.fire({ + text: confirmMessage, + icon: "error", + showCancelButton: true, + confirmButtonColor: "#008000", + cancelButtonColor: "#d33", + confirmButtonText: "Confirm", + }).then(function (result) { + if (result.isConfirmed) { + // var checkedRows = $(".all-time-sheet-row").filter(":checked"); + // ids = []; + // checkedRows.each(function () { + // ids.push($(this).attr("id")); + // }); + + $.ajax({ + type: "POST", + url: "/project/time-sheet-bulk-delete", + data: { + csrfmiddlewaretoken: getCookie("csrftoken"), + ids: JSON.stringify(ids), + }, + success: function (response, textStatus, jqXHR) { + if (jqXHR.status === 200) { + location.reload(); // Reload the current page + } else { + // console.log("Unexpected HTTP status:", jqXHR.status); + } + }, + }); + } + }); + } + }); }; diff --git a/project/templates/cbv/projects/actions.html b/project/templates/cbv/projects/actions.html index 9ccc5973a..fa8a58088 100644 --- a/project/templates/cbv/projects/actions.html +++ b/project/templates/cbv/projects/actions.html @@ -1,70 +1,70 @@ -{% load i18n %} -{% load taskfilters %} -
- {% if perms.project.change_project or request.user|is_project_manager:instance %} - - - - {% else %} - - {% endif %} - {% if perms.project.delete_project or request.user|is_project_manager:instance %} - {% if instance.is_active %} - - - - {% else %} - - - - {% endif %} - {% endif %} - {% if perms.project.delete_project %} - - - - {% endif %} +{% load i18n %} +{% load taskfilters %} +
+ {% if perms.project.change_project or request.user|is_project_manager:instance %} + + + + {% else %} + + {% endif %} + {% if perms.project.delete_project or request.user|is_project_manager:instance %} + {% if instance.is_active %} + + + + {% else %} + + + + {% endif %} + {% endif %} + {% if perms.project.delete_project %} + + + + {% endif %}
diff --git a/project/templates/cbv/projects/filter.html b/project/templates/cbv/projects/filter.html index 6dc13c40f..6974ec167 100644 --- a/project/templates/cbv/projects/filter.html +++ b/project/templates/cbv/projects/filter.html @@ -1,40 +1,40 @@ -{% load i18n%} -
-
-
{% trans "Project" %}
-
-
-
-
- - {{form.managers}} -
-
- - {{form.status}} -
-
- - {{form.start_from}} -
-
-
-
- - {{form.members}} -
-
- - {{form.is_active}} -
-
- - {{form.end_till}} -
-
-
-
-
+{% load i18n%} +
+
+
{% trans "Project" %}
+
+
+
+
+ + {{form.managers}} +
+
+ + {{form.status}} +
+
+ + {{form.start_from}} +
+
+
+
+ + {{form.members}} +
+
+ + {{form.is_active}} +
+
+ + {{form.end_till}} +
+
+
+
+
diff --git a/project/templates/cbv/projects/project_details.html b/project/templates/cbv/projects/project_details.html index cd3385a15..fa8e083ba 100644 --- a/project/templates/cbv/projects/project_details.html +++ b/project/templates/cbv/projects/project_details.html @@ -1,125 +1,125 @@ -{% load mathfilters %} -{% load static i18n %} -{% load taskfilters %} -
-
-
-
    -
  • - {% trans "Project:" %} - {{project}} -
  • -
- - - {% if perms.pms.change_project or request.user|is_project_manager_or_member:project %} - - {% else %} - - {% endif %} - {% if perms.project.change_project or perms.project.add_projectstage or request.user|is_project_manager_or_member:project %} -
- {% if perms.project.add_project %} - - {% endif %} -
- {% endif %} -
-
- -
    -
  • - {% trans "Managers:" %} - -
    -
    - {% for manager in project.managers.all %} - - {% endfor %} -
    -
    -
    -
  • -
  • - {% trans "Members:" %} - -
    -
    - {% for menber in project.members.all %} - - {% endfor %} -
    -
    -
    -
  • -
  • - {% trans "Start date:" %} - {{project.start_date}} - -
  • -
  • - {% trans "End date:" %} - {{project.end_date}} - - - - - -
  • -
  • -
    -
    - {% trans "Description:" %} -
    -
    - - -

    - {{project.description}} -

    -
    - -
    -
  • -
-
+{% load mathfilters %} +{% load static i18n %} +{% load taskfilters %} +
+
+
+
    +
  • + {% trans "Project:" %} + {{project}} +
  • +
+ + + {% if perms.pms.change_project or request.user|is_project_manager_or_member:project %} + + {% else %} + + {% endif %} + {% if perms.project.change_project or perms.project.add_projectstage or request.user|is_project_manager_or_member:project %} +
+ {% if perms.project.add_project %} + + {% endif %} +
+ {% endif %} +
+
+ +
    +
  • + {% trans "Managers:" %} + +
    +
    + {% for manager in project.managers.all %} + + {% endfor %} +
    +
    +
    +
  • +
  • + {% trans "Members:" %} + +
    +
    + {% for menber in project.members.all %} + + {% endfor %} +
    +
    +
    +
  • +
  • + {% trans "Start date:" %} + {{project.start_date}} + +
  • +
  • + {% trans "End date:" %} + {{project.end_date}} + + + + + +
  • +
  • +
    +
    + {% trans "Description:" %} +
    +
    + + +

    + {{project.description}} +

    +
    + +
    +
  • +
+
diff --git a/project/templates/cbv/projects/project_list.html b/project/templates/cbv/projects/project_list.html index f5985c68f..0ba23fd08 100644 --- a/project/templates/cbv/projects/project_list.html +++ b/project/templates/cbv/projects/project_list.html @@ -1,37 +1,37 @@ -{% load basefilters i18n %} -{% for project in projects %} -
-
-
- -
-
- {{ project.title }} -
-
-
- - - -
-
-
-
-
-
-
-
-{% endfor %} +{% load basefilters i18n %} +{% for project in projects %} +
+
+
+ +
+
+ {{ project.title }} +
+
+
+ + + +
+
+
+
+
+
+
+
+{% endfor %} diff --git a/project/templates/cbv/projects/project_nav.html b/project/templates/cbv/projects/project_nav.html index a4969b1e0..c893659f4 100644 --- a/project/templates/cbv/projects/project_nav.html +++ b/project/templates/cbv/projects/project_nav.html @@ -1,9 +1,9 @@ -{% load i18n %} -
- {% include "generic/horilla_nav.html" %} -
- - diff --git a/project/templates/cbv/projects/project_tab.html b/project/templates/cbv/projects/project_tab.html index 140dd7c45..c4931f7d8 100644 --- a/project/templates/cbv/projects/project_tab.html +++ b/project/templates/cbv/projects/project_tab.html @@ -1,19 +1,19 @@ -{% load i18n %} {% load static %} -
-{% if projects %} -
-

{% trans "Projects" %}

-
-
-{% include "cbv/projects/project_list.html" %} -
-{% else %} -
-
- Page not found. 404. -

{% trans "No projects assigned to this employee." %}

-
-
+{% load i18n %} {% load static %} +
+{% if projects %} +
+

{% trans "Projects" %}

+
+
+{% include "cbv/projects/project_list.html" %} +
+{% else %} +
+
+ Page not found. 404. +

{% trans "No projects assigned to this employee." %}

+
+
{% endif %} diff --git a/project/templates/cbv/projects/projects.html b/project/templates/cbv/projects/projects.html index 07e8ecdf8..60beaa810 100644 --- a/project/templates/cbv/projects/projects.html +++ b/project/templates/cbv/projects/projects.html @@ -1,149 +1,149 @@ -{% extends "index.html" %} -{% load i18n %}{% load static %} - - -{% block content %} - - - - - -
-
- - -{% include "generic/components.html" %} - - - - - -
-
-
-
- - - - - - - - +{% extends "index.html" %} +{% load i18n %}{% load static %} + + +{% block content %} + + + + + +
+
+ + +{% include "generic/components.html" %} + + + + + +
+
+
+
+ + + + + + + + {% endblock %} diff --git a/project/templates/cbv/tasks/task_actions.html b/project/templates/cbv/tasks/task_actions.html index 0fef6080e..54bf09d25 100644 --- a/project/templates/cbv/tasks/task_actions.html +++ b/project/templates/cbv/tasks/task_actions.html @@ -1,51 +1,51 @@ -{% load i18n %} -{% load taskfilters %} -
- {% if request.user|task_crud_perm:instance or perms.project.view_task %} -
- - - - {% if instance.is_active %} - - - - {% else %} - - - - {% endif %} -
- {% csrf_token %} - -
- - -
- {% else %} -
- - - - - - - - - -
- {% endif %} +{% load i18n %} +{% load taskfilters %} +
+ {% if request.user|task_crud_perm:instance or perms.project.view_task %} +
+ + + + {% if instance.is_active %} + + + + {% else %} + + + + {% endif %} +
+ {% csrf_token %} + +
+ + +
+ {% else %} +
+ + + + + + + + + +
+ {% endif %}
diff --git a/project/templates/cbv/tasks/task_detail_actions.html b/project/templates/cbv/tasks/task_detail_actions.html index 0e6fe4d20..3fcded097 100644 --- a/project/templates/cbv/tasks/task_detail_actions.html +++ b/project/templates/cbv/tasks/task_detail_actions.html @@ -1,27 +1,27 @@ -{% load i18n %} -{% if request.user|task_crud_perm:instance or perms.project.view_task %} - - - - {% trans "Edit" %} - -{% endif %} - - - - {% trans "Time sheet" %} - -{% if request.user|task_crud_perm:instance or perms.project.view_task %} - - - {% trans "Delete" %} - +{% load i18n %} +{% if request.user|task_crud_perm:instance or perms.project.view_task %} + + + + {% trans "Edit" %} + +{% endif %} + + + + {% trans "Time sheet" %} + +{% if request.user|task_crud_perm:instance or perms.project.view_task %} + + + {% trans "Delete" %} + {% endif %} diff --git a/project/templates/cbv/tasks/task_document.html b/project/templates/cbv/tasks/task_document.html index cdf34b3f2..4ac9ac7ca 100644 --- a/project/templates/cbv/tasks/task_document.html +++ b/project/templates/cbv/tasks/task_document.html @@ -1,10 +1,10 @@ -{% load i18n %} -{% if instance.document %} - {% trans "Document" %} -
- - -
+{% load i18n %} +{% if instance.document %} + {% trans "Document" %} +
+ + +
{% endif%} diff --git a/project/templates/cbv/tasks/task_filter.html b/project/templates/cbv/tasks/task_filter.html index 71e70840b..13d8f1ae3 100644 --- a/project/templates/cbv/tasks/task_filter.html +++ b/project/templates/cbv/tasks/task_filter.html @@ -1,41 +1,41 @@ -{% load i18n %} {% load basefilters %} -
-
-
- {% trans "Task" %} -
-
-
-
-
- - {{form.task_manager}} -
-
- - {{form.stage}} -
-
-
-
- - {{form.project}} -
-
- - {{form.status}} -
-
-
-
- - {{form.end_till}} -
-
- - -
-
-
+{% load i18n %} {% load basefilters %} +
+
+
+ {% trans "Task" %} +
+
+
+
+
+ + {{form.task_manager}} +
+
+ + {{form.stage}} +
+
+
+
+ + {{form.project}} +
+
+ + {{form.status}} +
+
+
+
+ + {{form.end_till}} +
+
+ + +
+
+
diff --git a/project/templates/cbv/tasks/task_form.html b/project/templates/cbv/tasks/task_form.html index 151d117ac..335e82ebb 100644 --- a/project/templates/cbv/tasks/task_form.html +++ b/project/templates/cbv/tasks/task_form.html @@ -1,9 +1,9 @@ -
- - {% include 'generic/horilla_form.html' %} +
+ + {% include 'generic/horilla_form.html' %}
diff --git a/project/templates/cbv/tasks/task_template_view.html b/project/templates/cbv/tasks/task_template_view.html index 86c45eb41..d01a9b275 100644 --- a/project/templates/cbv/tasks/task_template_view.html +++ b/project/templates/cbv/tasks/task_template_view.html @@ -1,125 +1,125 @@ -{% extends "index.html" %} -{% load i18n %}{% load static %} - - -{% block content %} - - - - - -
-
- - -{% include "generic/components.html" %} - - - - - -
-
-
-
- - - - - - - - - - - - - - - - - - - +{% extends "index.html" %} +{% load i18n %}{% load static %} + + +{% block content %} + + + + + +
+
+ + +{% include "generic/components.html" %} + + + + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + {% endblock %} diff --git a/project/templates/cbv/timesheet/actions.html b/project/templates/cbv/timesheet/actions.html index 654114c7e..c68261776 100644 --- a/project/templates/cbv/timesheet/actions.html +++ b/project/templates/cbv/timesheet/actions.html @@ -1,58 +1,58 @@ -{% load i18n %} {% load taskfilters %} -{% if request.user|time_sheet_crud_perm:instance or perms.project.change_timesheet or perms.project.delete_timesheet %} -
- - - - {% if request.task_id %} - - - - {% else %} - - - - {% endif %} -
-{% else %} -
- - - - - - - -
-{% endif %} +{% load i18n %} {% load taskfilters %} +{% if request.user|time_sheet_crud_perm:instance or perms.project.change_timesheet or perms.project.delete_timesheet %} +
+ + + + {% if request.task_id %} + + + + {% else %} + + + + {% endif %} +
+{% else %} +
+ + + + + + + +
+{% endif %} diff --git a/project/templates/cbv/timesheet/detail_actions.html b/project/templates/cbv/timesheet/detail_actions.html index 91e225568..c95cd8452 100644 --- a/project/templates/cbv/timesheet/detail_actions.html +++ b/project/templates/cbv/timesheet/detail_actions.html @@ -1,23 +1,23 @@ -{% load i18n %} -{% load basefilters %} -
- - - {% trans "Edit" %} - - {% if perms.project.view_timesheet or request.user|is_reportingmanager %} - - - {% trans "View Timesheet Chart" %} - - {% endif %} - - - {% trans "Delete" %} - +{% load i18n %} +{% load basefilters %} +
+ + + {% trans "Edit" %} + + {% if perms.project.view_timesheet or request.user|is_reportingmanager %} + + + {% trans "View Timesheet Chart" %} + + {% endif %} + + + {% trans "Delete" %} +
diff --git a/project/templates/cbv/timesheet/employee_field.html b/project/templates/cbv/timesheet/employee_field.html index 9101bba3c..80f3e70d2 100644 --- a/project/templates/cbv/timesheet/employee_field.html +++ b/project/templates/cbv/timesheet/employee_field.html @@ -1,29 +1,29 @@ -{% load i18n %} - -{{form.employee_id}} - diff --git a/project/templates/cbv/timesheet/filter.html b/project/templates/cbv/timesheet/filter.html index ac9e1e3d0..abd72ebea 100644 --- a/project/templates/cbv/timesheet/filter.html +++ b/project/templates/cbv/timesheet/filter.html @@ -1,59 +1,59 @@ -{% load i18n %}{% load basefilters%} -
-
-
{% trans "Time Sheet" %}
-
-
-
-
- - {{form.project_id}} -
-
- - {{form.status}} -
-
- -
-
- - {{form.task}} -
-
- - {{form.date}} -
-
- {% if perms.project.view_timesheet or request.user|is_reportingmanager %} -
-
- - {{form.employee_id}} -
-
- {% endif %} -
-
-
- -
-
{% trans "Advanced" %}
-
-
-
-
- - {{form.start_from}} -
-
-
-
- - {{form.end_till}} -
-
-
-
-
+{% load i18n %}{% load basefilters%} +
+
+
{% trans "Time Sheet" %}
+
+
+
+
+ + {{form.project_id}} +
+
+ + {{form.status}} +
+
+ +
+
+ + {{form.task}} +
+
+ + {{form.date}} +
+
+ {% if perms.project.view_timesheet or request.user|is_reportingmanager %} +
+
+ + {{form.employee_id}} +
+
+ {% endif %} +
+
+
+ +
+
{% trans "Advanced" %}
+
+
+
+
+ + {{form.start_from}} +
+
+
+
+ + {{form.end_till}} +
+
+
+
+
diff --git a/project/templates/cbv/timesheet/form.html b/project/templates/cbv/timesheet/form.html index e4b885488..d8abb2ffd 100644 --- a/project/templates/cbv/timesheet/form.html +++ b/project/templates/cbv/timesheet/form.html @@ -1,3 +1,3 @@ -
- {% include "generic/horilla_form.html" %} -
+
+ {% include "generic/horilla_form.html" %} +
diff --git a/project/templates/cbv/timesheet/task_field.html b/project/templates/cbv/timesheet/task_field.html index e61c27afa..418b90fb3 100644 --- a/project/templates/cbv/timesheet/task_field.html +++ b/project/templates/cbv/timesheet/task_field.html @@ -1,15 +1,15 @@ -{% load i18n %} - -
- {{form.task_id}} -
- diff --git a/project/templates/cbv/timesheet/task_timesheet.html b/project/templates/cbv/timesheet/task_timesheet.html index b9c5476a7..5747c3505 100644 --- a/project/templates/cbv/timesheet/task_timesheet.html +++ b/project/templates/cbv/timesheet/task_timesheet.html @@ -1,37 +1,37 @@ -{% load i18n %} -
- {% include "generic/components.html" %} -
- -
{% trans "Time sheet" %}
-
- {% comment %} for add timesheet {% endcomment %} - - - {% include "generic/horilla_list_table.html" %} -
+{% load i18n %} +
+ {% include "generic/components.html" %} +
+ +
{% trans "Time sheet" %}
+
+ {% comment %} for add timesheet {% endcomment %} + + + {% include "generic/horilla_list_table.html" %} +
diff --git a/project/templates/cbv/timesheet/timesheet_nav.html b/project/templates/cbv/timesheet/timesheet_nav.html index 9a96bb976..b9a6ae4cc 100644 --- a/project/templates/cbv/timesheet/timesheet_nav.html +++ b/project/templates/cbv/timesheet/timesheet_nav.html @@ -1,8 +1,8 @@ -{% load i18n %} -
- {% include "generic/horilla_nav.html" %} -
- diff --git a/project/templates/dashboard/project_dashboard.html b/project/templates/dashboard/project_dashboard.html index 216be36b5..96167b216 100644 --- a/project/templates/dashboard/project_dashboard.html +++ b/project/templates/dashboard/project_dashboard.html @@ -1,143 +1,143 @@ -{% extends 'index.html' %} -{% block content %} -{% load static i18n %} -{% load i18n %} - -
-
-
-
-
- -
-
-
- {% trans "Total Projects" %} -
- -
-
- -
-
-
- {% trans "New Projects" %} -
- -
-
- -
-
-
- {% trans "Projects in progress" %} -
- -
-
-
- -
- -
-
-
- {% trans "Project Status" %} - -
-
- -
-
-
- -
-
-
- {% trans "Task Status" %} - - -
-
- -
-
-
- -
-
- - -
- -
-
    -
  • -
  • -
  • -
  • -
-
-
-
- {% trans "Projects due in this month" %} -
-
-
-
-
-
-
-
-
- -
- - - - +{% extends 'index.html' %} +{% block content %} +{% load static i18n %} +{% load i18n %} + +
+
+
+
+
+ +
+
+
+ {% trans "Total Projects" %} +
+ +
+
+ +
+
+
+ {% trans "New Projects" %} +
+ +
+
+ +
+
+
+ {% trans "Projects in progress" %} +
+ +
+
+
+ +
+ +
+
+
+ {% trans "Project Status" %} + +
+
+ +
+
+
+ +
+
+
+ {% trans "Task Status" %} + + +
+
+ +
+
+
+ +
+
+ + +
+ +
+
    +
  • +
  • +
  • +
  • +
+
+
+
+ {% trans "Projects due in this month" %} +
+
+
+
+
+
+
+
+
+ +
+ + + + {% endblock content %} diff --git a/project/templates/dashboard/project_details.html b/project/templates/dashboard/project_details.html index b7f2ca66a..64d1d3052 100644 --- a/project/templates/dashboard/project_details.html +++ b/project/templates/dashboard/project_details.html @@ -1,71 +1,71 @@ -{% load i18n %} {% load horillafilters %} - -
- -
{{project.title}}
-
- -
-
- {% trans "Manager" %} - {{project.manager}} -
-
- {% trans "Members" %} - {% for member in project.members.all %}{{member}}, {% endfor %} -
-
-
-
- {% trans "Status" %} - {{project.get_status_display}} -
-
- {% trans "No of Tasks" %} - {{task_count}} -
-
-
-
- {% trans "Start Date" %} - {{project.start_date}} -
-
- {% trans "End date" %} - {{project.end_date}} -
-
-
-
- {% trans "Document" %} - {{project.document}} -
-
- {% trans "Description" %} - {{project.description}} -
-
-
- {% comment %}
{% endcomment %} - - - {% trans "View" %} - - {% comment %}
{% endcomment %} -
- +{% load i18n %} {% load horillafilters %} + +
+ +
{{project.title}}
+
+ +
+
+ {% trans "Manager" %} + {{project.manager}} +
+
+ {% trans "Members" %} + {% for member in project.members.all %}{{member}}, {% endfor %} +
+
+
+
+ {% trans "Status" %} + {{project.get_status_display}} +
+
+ {% trans "No of Tasks" %} + {{task_count}} +
+
+
+
+ {% trans "Start Date" %} + {{project.start_date}} +
+
+ {% trans "End date" %} + {{project.end_date}} +
+
+
+
+ {% trans "Document" %} + {{project.document}} +
+
+ {% trans "Description" %} + {{project.description}} +
+
+
+ {% comment %}
{% endcomment %} + + + {% trans "View" %} + + {% comment %}
{% endcomment %} +
+
diff --git a/project/templates/project/new/filter_project.html b/project/templates/project/new/filter_project.html index 85e5ca2b1..10ff0d734 100644 --- a/project/templates/project/new/filter_project.html +++ b/project/templates/project/new/filter_project.html @@ -1,44 +1,44 @@ -{% load i18n %} {% load basefilters %} -{% comment %}
{% endcomment %} -
-
-
{% trans "Project" %}
-
-
-
-
- - {{f.form.manager}} -
-
- - {{f.form.status}} -
-
-
-
- - {{f.form.start_from}} -
-
- - {{f.form.end_till}} -
-
- -
-
-
-
- +{% load i18n %} {% load basefilters %} +{% comment %} {% endcomment %} +
+
+
{% trans "Project" %}
+
+
+
+
+ + {{f.form.manager}} +
+
+ + {{f.form.status}} +
+
+
+
+ + {{f.form.start_from}} +
+
+ + {{f.form.end_till}} +
+
+ +
+
+
+
+ {% comment %}
{% endcomment %} diff --git a/project/templates/project/new/forms/project_creation.html b/project/templates/project/new/forms/project_creation.html index a940c4e8e..1791f1785 100644 --- a/project/templates/project/new/forms/project_creation.html +++ b/project/templates/project/new/forms/project_creation.html @@ -1,30 +1,30 @@ -{% load i18n %} -
- -
{% trans "Project" %}
-
-
- -
- {% csrf_token %} {{ form.as_p }} - -
+{% load i18n %} +
+ +
{% trans "Project" %}
+
+
+ +
+ {% csrf_token %} {{ form.as_p }} + +
diff --git a/project/templates/project/new/forms/project_update.html b/project/templates/project/new/forms/project_update.html index 9b28c6dc2..d2518f3a1 100644 --- a/project/templates/project/new/forms/project_update.html +++ b/project/templates/project/new/forms/project_update.html @@ -1,30 +1,30 @@ -{% load i18n %} -
- -
{% trans "Project" %}
-
-
- -
- {% csrf_token %} {{ form.as_p }} - -
+{% load i18n %} +
+ +
{% trans "Project" %}
+
+
+ +
+ {% csrf_token %} {{ form.as_p }} + +
diff --git a/project/templates/project/new/navbar.html b/project/templates/project/new/navbar.html index ab4e14553..56493cc82 100644 --- a/project/templates/project/new/navbar.html +++ b/project/templates/project/new/navbar.html @@ -1,234 +1,234 @@ -{% load i18n %} - - - - - -
-
-

{% trans "Projects" %}

- - - -
-
- {% if projects %} - {% comment %} for search{% endcomment %} -
-
- - -
-
-
    - {% comment %} for list view {% endcomment %} -
  • - -
  • - {% comment %} for card view {% endcomment %} -
  • - -
  • -
-
- {% comment %} for filtering {% endcomment %} -
- - -
-
- {% comment %} for actions {% endcomment %} -
-
- - -
-
- {% endif %} - {% comment %} for create project {% endcomment %} - -
-
+{% load i18n %} + + + + + +
+
+

{% trans "Projects" %}

+ + + +
+
+ {% if projects %} + {% comment %} for search{% endcomment %} +
+
+ + +
+
+
    + {% comment %} for list view {% endcomment %} +
  • + +
  • + {% comment %} for card view {% endcomment %} +
  • + +
  • +
+
+ {% comment %} for filtering {% endcomment %} +
+ + +
+
+ {% comment %} for actions {% endcomment %} +
+
+ + +
+
+ {% endif %} + {% comment %} for create project {% endcomment %} + +
+
diff --git a/project/templates/project/new/overall.html b/project/templates/project/new/overall.html index ea1fc2599..ccab0d6a8 100644 --- a/project/templates/project/new/overall.html +++ b/project/templates/project/new/overall.html @@ -1,33 +1,33 @@ -{% extends 'index.html' %} -{% load static %} -{% block content %} - -
- {% include 'project/new/navbar.html' %} -
- -
- - {% if view_type == 'list' %} - {% include 'project/new/project_list_view.html' %} - - {% else %} - {% include 'project/new/project_kanban_view.html' %} - {% endif %} -
- - - -{% endblock content %} +{% extends 'index.html' %} +{% load static %} +{% block content %} + +
+ {% include 'project/new/navbar.html' %} +
+ +
+ + {% if view_type == 'list' %} + {% include 'project/new/project_list_view.html' %} + + {% else %} + {% include 'project/new/project_kanban_view.html' %} + {% endif %} +
+ + + +{% endblock content %} diff --git a/project/templates/project/new/project_kanban_view.html b/project/templates/project/new/project_kanban_view.html index 5864eb278..405ad3dbc 100644 --- a/project/templates/project/new/project_kanban_view.html +++ b/project/templates/project/new/project_kanban_view.html @@ -1,201 +1,201 @@ - -{% load static %} - -{% load i18n %}{% load horillafilters %} -{% load basefilters %} - - -{% comment %} for showing messages {% endcomment %} -{% if messages %} -
- {% for message in messages %} -
- {{ message }} -
- {% endfor %} -
-{% endif %} -{% include "filter_tags.html" %} -{% comment %} easy filters {% endcomment %} -
- - - {% trans "New" %} - - - - {% trans "In progress" %} - - - - {% trans "Completed" %} - - - {% trans "On Hold" %} - - - - {% trans "Cancelled" %} - - - - {% trans "Expired" %} - -
- - - {% comment %} kanban view {% endcomment %} - {% if projects %} -
- {% for project in projects %} -
- - {% comment %} url link {% endcomment %} - - - {% comment %} placing image {% endcomment %} -
-
- {% if project.image %} - Username - {% else %} - Username - {% endif %} -
-
- -
- {{project.title}} - {% trans "Project manager" %} : {{project.manager}}
- {% trans "Status" %}: {{project.get_status_display}}
- {% trans "End date" %} : {{project.end_date}} -
-
-
- - {{ project.task_set.all|length}} - -
-
- - {% comment %} dropdown {% endcomment %} -
- - {% comment %} dropdown menu {% endcomment %} - - -
-
-
- {% endfor %} -
- {% comment %} pagination {% endcomment %} -
- - {% trans "Page" %} {{ projects.number }} {% trans "of" %} {{ projects.paginator.num_pages }}. - - -
-{% comment %}
{% endcomment %} - -{% else %} -
-
- Page not found. 404. -

{% trans "There are currently no available projects; please create a new one." %}

-
-
-{% endif %} - - -{% comment %} js scripts {% endcomment %} - + +{% load static %} + +{% load i18n %}{% load horillafilters %} +{% load basefilters %} + + +{% comment %} for showing messages {% endcomment %} +{% if messages %} +
+ {% for message in messages %} +
+ {{ message }} +
+ {% endfor %} +
+{% endif %} +{% include "filter_tags.html" %} +{% comment %} easy filters {% endcomment %} +
+ + + {% trans "New" %} + + + + {% trans "In progress" %} + + + + {% trans "Completed" %} + + + {% trans "On Hold" %} + + + + {% trans "Cancelled" %} + + + + {% trans "Expired" %} + +
+ + + {% comment %} kanban view {% endcomment %} + {% if projects %} +
+ {% for project in projects %} +
+ + {% comment %} url link {% endcomment %} + + + {% comment %} placing image {% endcomment %} +
+
+ {% if project.image %} + Username + {% else %} + Username + {% endif %} +
+
+ +
+ {{project.title}} + {% trans "Project manager" %} : {{project.manager}}
+ {% trans "Status" %}: {{project.get_status_display}}
+ {% trans "End date" %} : {{project.end_date}} +
+
+
+ + {{ project.task_set.all|length}} + +
+
+ + {% comment %} dropdown {% endcomment %} +
+ + {% comment %} dropdown menu {% endcomment %} + + +
+
+
+ {% endfor %} +
+ {% comment %} pagination {% endcomment %} +
+ + {% trans "Page" %} {{ projects.number }} {% trans "of" %} {{ projects.paginator.num_pages }}. + + +
+{% comment %}
{% endcomment %} + +{% else %} +
+
+ Page not found. 404. +

{% trans "There are currently no available projects; please create a new one." %}

+
+
+{% endif %} + + +{% comment %} js scripts {% endcomment %} + diff --git a/project/templates/project/new/project_list_view.html b/project/templates/project/new/project_list_view.html index 15be71637..d6672035f 100644 --- a/project/templates/project/new/project_list_view.html +++ b/project/templates/project/new/project_list_view.html @@ -1,236 +1,236 @@ - -{% load static %} -{% load i18n %} {% load horillafilters %} - - -{% comment %} for showing messages {% endcomment %} -{% if messages %} -
- {% for message in messages %} -
- {{ message }} -
- {% endfor %} -
-{% endif %} -{% include "filter_tags.html" %} - -
- {% if projects %} -
- {% comment %} easy filters {% endcomment %} -
- - - {% trans "New" %} - - - - {% trans "In progress" %} - - - - {% trans "Completed" %} - - - {% trans "On Hold" %} - - - - {% trans "Cancelled" %} - - - - {% trans "Expired" %} - -
- -
-
-
-
-
-
-
- -
-
- {% trans "Project" %} -
-
-
-
{% trans "Project Manager" %}
-
{% trans "Project Members" %}
-
{% trans "Status" %}
-
{% trans "Start Date" %}
-
{% trans "End Date" %}
-
{% trans "File" %}
-
{% trans "Description" %}
-
-
-
- - {% for project in projects %} -
-
-
- - {{project.title}} -
-
- -
{{project.manager}}
-
- {% for employee in project.members.all %} {{employee}}
- {% endfor %} -
-
{{project.get_status_display}}
-
{{project.start_date}}
-
{% if project.end_date %}{{project.end_date}}{% endif %}
-
{% if project.document %}document{% endif %}
-
{{project.description}}
- -
- -
-
- {% endfor %} - {% else %} -
-
- Page not found. 404. -

{% trans "There are currently no available projects; please create a new one." %}

-
-
- - {% endif %} - -
-
-
- {% comment %}
- - {% trans "Page" %} {{ allowances.number }} {% trans "of" %} {{ - allowances.paginator.num_pages }}. - - -
{% endcomment %} -
- - -{% comment %} js scripts {% endcomment %} - - - - + +{% load static %} +{% load i18n %} {% load horillafilters %} + + +{% comment %} for showing messages {% endcomment %} +{% if messages %} +
+ {% for message in messages %} +
+ {{ message }} +
+ {% endfor %} +
+{% endif %} +{% include "filter_tags.html" %} + +
+ {% if projects %} +
+ {% comment %} easy filters {% endcomment %} +
+ + + {% trans "New" %} + + + + {% trans "In progress" %} + + + + {% trans "Completed" %} + + + {% trans "On Hold" %} + + + + {% trans "Cancelled" %} + + + + {% trans "Expired" %} + +
+ +
+
+
+
+
+
+
+ +
+
+ {% trans "Project" %} +
+
+
+
{% trans "Project Manager" %}
+
{% trans "Project Members" %}
+
{% trans "Status" %}
+
{% trans "Start Date" %}
+
{% trans "End Date" %}
+
{% trans "File" %}
+
{% trans "Description" %}
+
+
+
+ + {% for project in projects %} +
+
+
+ + {{project.title}} +
+
+ +
{{project.manager}}
+
+ {% for employee in project.members.all %} {{employee}}
+ {% endfor %} +
+
{{project.get_status_display}}
+
{{project.start_date}}
+
{% if project.end_date %}{{project.end_date}}{% endif %}
+
{% if project.document %}document{% endif %}
+
{{project.description}}
+ +
+ +
+
+ {% endfor %} + {% else %} +
+
+ Page not found. 404. +

{% trans "There are currently no available projects; please create a new one." %}

+
+
+ + {% endif %} + +
+
+
+ {% comment %}
+ + {% trans "Page" %} {{ allowances.number }} {% trans "of" %} {{ + allowances.paginator.num_pages }}. + + +
{% endcomment %} +
+ + +{% comment %} js scripts {% endcomment %} + + + + diff --git a/project/templates/project_stage/forms/create_project_stage.html b/project/templates/project_stage/forms/create_project_stage.html index 06b3f1aab..732240b1e 100644 --- a/project/templates/project_stage/forms/create_project_stage.html +++ b/project/templates/project_stage/forms/create_project_stage.html @@ -1,30 +1,30 @@ -{% load i18n %} -
- -
{% trans "Project Stage" %}
-
-
- -
- {% csrf_token %} {{ form.as_p }} - -
+{% load i18n %} +
+ +
{% trans "Project Stage" %}
+
+
+ +
+ {% csrf_token %} {{ form.as_p }} + +
diff --git a/project/templates/project_stage/forms/update_project_stage.html b/project/templates/project_stage/forms/update_project_stage.html index fa0c38070..922dd7acf 100644 --- a/project/templates/project_stage/forms/update_project_stage.html +++ b/project/templates/project_stage/forms/update_project_stage.html @@ -1,30 +1,30 @@ -{% load i18n %} -
- -
{% trans "Project Stage" %}
-
-
- -
- {% csrf_token %} {{ form.as_p }}{{form.errorList}} - -
+{% load i18n %} +
+ +
{% trans "Project Stage" %}
+
+
+ +
+ {% csrf_token %} {{ form.as_p }}{{form.errorList}} + +
diff --git a/project/templates/task/new/filter_task.html b/project/templates/task/new/filter_task.html index 3c3bdaaa9..14c5018a0 100644 --- a/project/templates/task/new/filter_task.html +++ b/project/templates/task/new/filter_task.html @@ -1,44 +1,44 @@ -{% load i18n %} {% load basefilters %} -
-
-
{% trans "Task" %}
-
-
- -
-
- - {{f.form.task_managers}} -
-
- - {{f.form.stage}} -
-
-
-
- - {{f.form.task_members}} -
-
- - {{f.form.status}} -
-
-
-
- - {{f.form.end_till}} -
-
- -
-
-
-
-