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%}
-
-
-
-
-
-
-
-
- {{form.managers}}
-
-
-
- {{form.status}}
-
-
-
- {{form.start_from}}
-
-
-
-
-
- {{form.members}}
-
-
-
- {{form.is_active}}
-
-
-
- {{form.end_till}}
-
-
-
-
-
+{% load i18n%}
+
+
+
+
+
+
+
+
+ {{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 %}
-
-
+{% load mathfilters %}
+{% load static i18n %}
+{% load taskfilters %}
+
+
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 %}
-
-
-{% include "cbv/projects/project_list.html" %}
-
-{% else %}
-
-
-

-
{% trans "No projects assigned to this employee." %}
-
-
+{% load i18n %} {% load static %}
+
+{% if projects %}
+
+
+{% include "cbv/projects/project_list.html" %}
+
+{% else %}
+
+
+

+
{% 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 %}
-
-
-
-
- {% else %}
-
- {% endif %}
+{% load i18n %}
+{% load taskfilters %}
+
+ {% if request.user|task_crud_perm:instance or perms.project.view_task %}
+
+
+
+
+ {% if instance.is_active %}
+
+
+
+ {% else %}
+
+
+
+ {% endif %}
+
+
+
+
+ {% 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 %}
-
-
-
-
-
-
-
-
- {{form.task_manager}}
-
-
-
- {{form.stage}}
-
-
-
-
-
- {{form.project}}
-
-
-
- {{form.status}}
-
-
-
-
-
- {{form.end_till}}
-
-
-
-
-
-
-
+{% load i18n %} {% load basefilters %}
+
+
+
+
+
+
+
+
+ {{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 %}
+
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%}
-
-
-
-
-
-
-
-
- {{form.project_id}}
-
-
-
- {{form.status}}
-
-
-
-
-
-
- {{form.task}}
-
-
-
- {{form.date}}
-
-
- {% if perms.project.view_timesheet or request.user|is_reportingmanager %}
-
-
-
- {{form.employee_id}}
-
-
- {% endif %}
-
-
-
-
-
-
-
-
-
-
-
- {{form.start_from}}
-
-
-
-
-
- {{form.end_till}}
-
-
-
-
-
+{% load i18n %}{% load basefilters%}
+
+
+
+
+
+
+
+
+ {{form.project_id}}
+
+
+
+ {{form.status}}
+
+
+
+
+
+
+ {{form.task}}
+
+
+
+ {{form.date}}
+
+
+ {% if perms.project.view_timesheet or request.user|is_reportingmanager %}
+
+
+
+ {{form.employee_id}}
+
+
+ {% endif %}
+
+
+
+
+
+
+
+
+
+
+
+ {{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" %}
-
+{% load i18n %}
+
+ {% include "generic/components.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 %}
-
-
-
-
-
-
-
-
-
-
-
+{% extends 'index.html' %}
+{% block content %}
+{% load static i18n %}
+{% load i18n %}
+
+
+
+
+
+
+
+
+
+
+
{% 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 %}
-
-