CBV code updates

This commit is contained in:
Horilla
2025-03-24 11:56:55 +05:30
parent 03667802a7
commit 5e908ecb24
38 changed files with 320 additions and 321 deletions

View File

@@ -32,8 +32,8 @@ function toggleColumns(tableId, fieldContainer) {
}
let selectButtons = $(`
<div class="oh-dropdown_btn-header">
<button onclick="$(this).parent().parent().find('[type=checkbox]').prop('checked',true).change()" class="oh-btn oh-btn--success-outline">Select All Rows</button>
<button onclick="$(this).parent().parent().find('[type=checkbox]').prop('checked',false).change()" class="oh-btn oh-btn--primary-outline">Unselect All Rows</button>
<button onclick="$(this).parent().parent().find('[type=checkbox]').prop('checked',true).change()" class="oh-btn oh-btn--success-outline">Select All Columns</button>
<button onclick="$(this).parent().parent().find('[type=checkbox]').prop('checked',false).change()" class="oh-btn oh-btn--primary-outline">Unselect All Columns</button>
</div>
`)
$(`#${fieldContainer}`).parent().prepend(selectButtons)

View File

@@ -77,7 +77,7 @@
<tr>
<td style="width: 50%">
<img
src="{{protocol}}://{{host}}/{{instance.get_company.icon}}"
src="{{protocol}}://{{host}}/{{instance.get_company.icon.url}}"
height="30"
width="110.4"
/>

View File

@@ -398,5 +398,4 @@
if (!localStorageroratingShiftCells) {
$("#roratingShiftCells").find("[type=checkbox]").prop("checked", true);
}
$("[type=checkbox]").change();
</script>

View File

@@ -427,5 +427,4 @@
if (!localStorageWorkTypeReqCells) {
$("#workTypeRequestCells").find("[type=checkbox]").prop("checked", true);
}
$("[type=checkbox]").change();
</script>

View File

@@ -239,22 +239,21 @@ def load_demo_database(request):
"base_data.json",
"work_info_data.json",
]
optional_apps = {
"attendance": "attendance_data.json",
"leave": "leave_data.json",
"asset": "asset_data.json",
"recruitment": "recruitment_data.json",
"onboarding": "onboarding_data.json",
"offboarding": "offboarding_data.json",
"pms": "pms_data.json",
"payroll": "payroll_data.json",
}
optional_apps = [
("attendance", "attendance_data.json"),
("leave", "leave_data.json"),
("asset", "asset_data.json"),
("recruitment", "recruitment_data.json"),
("onboarding", "onboarding_data.json"),
("offboarding", "offboarding_data.json"),
("pms", "pms_data.json"),
("payroll", "payroll_data.json"),
("payroll", "payroll_loanaccount_data.json"),
]
# Add data files for installed apps
data_files += [
file
for app, file in optional_apps.items()
if apps.is_installed(app)
file for app, file in optional_apps if apps.is_installed(app)
]
# Load all data files

View File

@@ -2,7 +2,7 @@
CrossChexCloudAPI module for Anviz Biometric Integration
This module provides a wrapper for interacting with the CrossChex Cloud API to manage
authentication, attendance data retrieval, and token handling. It allows for secure
authentication, attendance data retrieval, and token handling. It allows for secure
communication with the API, including fetching and validating tokens, and retrieving
attendance records .
"""

View File

@@ -1,21 +1,20 @@
"""
DahuaAPI module for interacting with Dahua biometric and access control devices.
This module provides a set of methods for managing and configuring Dahua devices,
including retrieving system information, managing users, setting up network configurations,
and interacting with attendance logs. It communicates with Dahua devices via HTTP requests
This module provides a set of methods for managing and configuring Dahua devices,
including retrieving system information, managing users, setting up network configurations,
and interacting with attendance logs. It communicates with Dahua devices via HTTP requests
and supports basic operations such as system reboot, setting time, and language configuration.
"""
import re
from typing import Any, Dict
from datetime import datetime, timezone
from collections import defaultdict
from datetime import datetime, timezone
from typing import Any, Dict
import requests
from requests.auth import HTTPDigestAuth
key_map = {
"AttendanceState": "attendance_state",
"CardID": "card_id",

View File

@@ -30,4 +30,4 @@
$(this).closest("select")[0].dispatchEvent(new Event("change"));
});
});
</script>
</script>

View File

@@ -60,4 +60,4 @@
</div>
{% endfor %}
</div>
</div>
</div>

View File

@@ -22,4 +22,4 @@
</button>
</div>
</form>
</div>
</div>

View File

@@ -57,4 +57,4 @@
</div>
</div>
</div>
</section>
</section>

View File

@@ -20,4 +20,4 @@
<span hx-delete="{% url 'delete-dahua-user' %}" hx-vals="" id="deleteDahuaUsers"></span>
</div>
<script src="{% static 'actions.js' %}"></script>
{% endblock %}
{% endblock %}

View File

@@ -4,39 +4,37 @@ employee/cbv/allocations.py
Detailed view to manage all modules employee information
"""
import logging
import ast
from django.http import HttpResponse
import logging
from datetime import datetime
from django.contrib import messages
from django.db.models import Q
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.http import HttpResponse
from django.shortcuts import render
from django.urls import reverse_lazy
from django.db.models.signals import post_save
from django.utils.decorators import method_decorator
from django.dispatch import receiver
from django.db.models import Q
from django.utils.translation import gettext as _
from django.views.generic import View
from employee.models import (
Employee,
EmployeeWorkInformation,
EmployeeBankDetails,
models as django_models,
)
from employee.methods.methods import get_model_class
from horilla_views.cbv_methods import render_template, login_required
from horilla_views.generic.cbv.views import (
HorillaDetailedView,
HorillaListView,
TemplateView,
HorillaFormView,
)
from horilla.horilla_middlewares import _thread_locals
from horilla.horilla_settings import APPS, NO_PERMISSION_MODALS
from base.forms import AddToUserGroupForm, ModelForm, forms
from base.methods import paginator_qry
from base.templatetags.horillafilters import app_installed
from base.views import get_models_in_app
from employee.methods.methods import get_model_class
from employee.models import Employee, EmployeeBankDetails, EmployeeWorkInformation
from employee.models import models as django_models
from horilla.horilla_middlewares import _thread_locals
from horilla.horilla_settings import APPS, NO_PERMISSION_MODALS
from horilla_views.cbv_methods import login_required, render_template
from horilla_views.generic.cbv.views import (
HorillaDetailedView,
HorillaFormView,
HorillaListView,
TemplateView,
)
if app_installed("asset"):
from asset.cbv.request_and_allocation import Asset
@@ -45,18 +43,17 @@ if app_installed("asset"):
from asset.views import asset_allocate_return
from asset.forms import AssetReturnForm
from onboarding.cbv_decorators import (
all_manager_can_enter,
recruitment_manager_can_enter,
)
if app_installed("leave"):
from leave.cbv.leave_types import LeaveTypeListView, LeaveType, AvailableLeave
from leave.cbv.leave_types import AvailableLeave, LeaveType, LeaveTypeListView
if app_installed("payroll"):
from payroll.cbv.allowances import AllowanceListView, Allowance
from payroll.cbv.deduction import DeductionListView, Deduction
from payroll.cbv.allowances import Allowance, AllowanceListView
from payroll.cbv.deduction import Deduction, DeductionListView
logger = logging.getLogger(__name__)
@@ -557,11 +554,14 @@ if app_installed("leave"):
avaiable_instance.available_days = leave_type.total_days
try:
avaiable_instance.save()
messages.success(self.request, _("Assigned ") + f" {leave_type.name}")
messages.success(
self.request, _("Assigned ") + f" {leave_type.name}"
)
except:
messages.error(
self.request,
_("Cannot Assign or Already Assigned") + f" `{leave_type.name}`",
_("Cannot Assign or Already Assigned")
+ f" `{leave_type.name}`",
)
if not types:
messages.info(self.request, _("Select Types to Assign"))
@@ -937,7 +937,9 @@ if app_installed("payroll"):
allowance.exclude_employees.add(self.instance)
allowance.specific_employees.remove(self.instance)
messages.success(self.request, _("Allowance excluded") + f" {allowance}")
messages.success(
self.request, _("Allowance excluded") + f" {allowance}"
)
else:
ids = ast.literal_eval(self.request.POST["ids"])
allowances = Allowance.objects.filter(pk__in=ids)
@@ -1040,7 +1042,9 @@ if app_installed("payroll"):
deduction.exclude_employees.add(self.instance)
deduction.specific_employees.remove(self.instance)
messages.success(self.request, _("Deduction excluded") + f" {deduction}")
messages.success(
self.request, _("Deduction excluded") + f" {deduction}"
)
else:
ids = ast.literal_eval(self.request.POST["ids"])
deductions = Deduction.objects.filter(pk__in=ids)

View File

@@ -39,7 +39,7 @@
{% endif %}
</li>
{% endfor %}
</ul>
</div>
</div>

View File

@@ -13,4 +13,4 @@
</span>
</div> {% endcomment %}
Available
{% endif %}
{% endif %}

View File

@@ -3,15 +3,15 @@
<div class="oh-main__titlebar oh-main__titlebar--right justify-content-between align-items-center">
<div class="oh-input-group oh-input__search-group" style="margin-left: -15px;" :class="searchShow ? 'oh-input__search-group--show' : ''">
<ion-icon name="search-outline" class="oh-input-group__icon oh-input-group__icon--left md hydrated" role="img" aria-label="search outline"></ion-icon>
<input
type="text"
<input
type="text"
hx-get="{% url "allocation-asset-list" %}?instance_id={{request.GET.instance_id}}"
hx-trigger="keyup changed delay:.100s"
hx-target="#typesContainer"
autocomplete="false"
name="search"
class="oh-input oh-input__icon"
aria-label="Search Input"
class="oh-input oh-input__icon"
aria-label="Search Input"
placeholder="Search" />
</div>
</div>
@@ -31,7 +31,7 @@
</div>
</div>
<div class="oh-modal__dialog-footer p-0">
<button type="submit"
<button type="submit"
onclick="
ids = $('#selectedInstances').attr('data-ids')
$('.oh-inner-sidebar-content [name=ids]').val(ids);
@@ -41,7 +41,7 @@
</div>
</div>
</div>
<div id="responseContainer" hidden>
</div>
</div>

View File

@@ -63,7 +63,7 @@
>
{% trans "Add Report" %}
</button>
{% if "payroll"|app_installed %}
{% if "payroll"|app_installed %}
{% if perms.payroll.add_loanaccount %}
<button
class="oh-btn oh-btn--primary oh-btn--shadow w-100 ml-2"

View File

@@ -33,7 +33,7 @@
})
</script>
{% if perms.auth.add_permission or perms.auth.change_permission or perms.auth.delete_permission %}
{% load i18n %}
{% load i18n %}
{% for perm in permissions %}
<span type="button" class="perm-accordion w-100 p-2 oh-user_permission-list_item app-permissions" onclick="$(this).next().toggle();$(this).toggleClass('perm-accordion-active');">
<div class="d-flex flex-row bd-highlight">
@@ -160,7 +160,7 @@
if (!$(this).is(':checked')) {
$(this).closest('.oh-sticky-table__tr').find('.row-permission').prop('checked',false)
}
"
"
data-group-id="{{group.id}}"
data-group-name="{{group.name}}"
/>
@@ -195,7 +195,7 @@
</div>
</div>
{% endfor %}
{% endif %}
</div>
</div>
@@ -357,7 +357,7 @@
</h2>
{% if perms.auth.change_group %}
<button class="oh-btn oh-btn--danger" hx-get="{% url "allocation-assign-group-user" %}" hx-vals='{"employee":"{{employee.id}}"}' hx-target="#groupAssignBody" data-toggle="oh-modal-toggle" data-target="#groupAssign" onclick="event.stopPropagation()" title="Assign user groups">
<ion-icon name="person-add-outline" class="text-light">Add</ion-icon>
<ion-icon name="person-add-outline" class="text-light">Add</ion-icon>
</button>
{% endif %}
</div>

View File

@@ -49,7 +49,7 @@
})
</script>
{% if perms.auth.add_permission or perms.auth.change_permission or perms.auth.delete_permission %}
{% load i18n %}
{% load i18n %}
{% for perm in permissions %}
<span type="button" class="perm-accordion w-100 p-2 oh-user_permission-list_item app-permissions" onclick="$(this).next().toggle();$(this).toggleClass('perm-accordion-active');">
<div class="d-flex flex-row bd-highlight">
@@ -176,7 +176,7 @@
if (!$(this).is(':checked')) {
$(this).closest('.oh-sticky-table__tr').find('.row-permission').prop('checked',false)
}
"
"
data-group-id="{{group.id}}"
data-group-name="{{group.name}}"
/>
@@ -211,7 +211,7 @@
</div>
</div>
{% endfor %}
{% endif %}
</div>
</div>
@@ -363,4 +363,4 @@
}
})
}
</script>
</script>

View File

@@ -35,7 +35,7 @@
<div class="oh-switch" style="width: 30px">
{{ field|add_class:'oh-switch__checkbox' }}
</div>
{% else %}
{% else %}
<div id="dynamic_field_{{field.name}}">
{{ field|add_class:'form-control' }}
{{ field.errors }}

View File

@@ -46,4 +46,4 @@
$(".oh-inner-sidebar-content__header:visible .oh-general__tab:first span").click();
}, 100);
});
</script>
</script>

View File

@@ -26,6 +26,5 @@
</div>
</div>
</div>
<div id="responseContainer" hidden></div>

View File

@@ -26,6 +26,5 @@
</div>
</div>
</div>
<div id="responseContainer" hidden></div>

View File

@@ -124,7 +124,7 @@
<div class="oh-card__body">
<div class="row">
<div class="col-12 col-sm-12" hx-get="{% url "allocation-deduction-list" %}?instance_id={{instance.pk}}&card_only=true" hx-trigger="load">
</div>
</div>
</div>
</div>
</div>

View File

@@ -2917,7 +2917,7 @@ def get_employees_birthday(request):
else f"{default_avatar_url}{emp.employee_first_name}+{emp.employee_last_name}"
),
"name": f"{emp.employee_first_name} {emp.employee_last_name}",
"dob": emp.dob.strftime("%d %b %Y"),
"dob": emp.dob.strftime("%d %b"),
"daysUntilBirthday": (
_("Today")
if emp.days_until_birthday == 0

View File

@@ -4,14 +4,17 @@ import atexit
def shutdown_function():
from horilla_backup.models import GoogleDriveBackup, LocalBackup
if GoogleDriveBackup.objects.exists():
google_drive_backup = GoogleDriveBackup.objects.first()
google_drive_backup.active = False
google_drive_backup.save()
if LocalBackup.objects.exists():
local_backup = LocalBackup.objects.first()
local_backup.active = False
local_backup.save()
try:
if GoogleDriveBackup.objects.exists():
google_drive_backup = GoogleDriveBackup.objects.first()
google_drive_backup.active = False
google_drive_backup.save()
if LocalBackup.objects.exists():
local_backup = LocalBackup.objects.first()
local_backup.active = False
local_backup.save()
except:
pass
try:

View File

@@ -1592,32 +1592,5 @@
"status": "requested",
"description": "Software license for Sublime Text (1-year subscription for team development)."
}
},
{
"model": "payroll.loanaccount",
"pk": 1,
"fields": {
"created_at": "2024-12-12T09:45:26.097Z",
"created_by": 1,
"modified_by": 1,
"is_active": true,
"type": "loan",
"title": "Medical Loan",
"employee_id": 18,
"loan_amount": 60000.0,
"provided_date": "2024-12-01",
"allowance_id": 5,
"description": "Loan for parents medical case",
"is_fixed": true,
"rate": 0.0,
"installment_amount": 5000.0,
"installments": 12,
"installment_start_date": "2025-01-01",
"apply_on": "end_of_month",
"settled": false,
"settled_date": null,
"asset_id": null,
"deduction_ids": [22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33]
}
}
]

View File

@@ -0,0 +1,29 @@
[
{
"model": "payroll.loanaccount",
"pk": 1,
"fields": {
"created_at": "2024-12-12T09:45:26.097Z",
"created_by": 1,
"modified_by": 1,
"is_active": true,
"type": "loan",
"title": "Medical Loan",
"employee_id": 18,
"loan_amount": 60000.0,
"provided_date": "2024-12-01",
"allowance_id": 5,
"description": "Loan for parents medical case",
"is_fixed": true,
"rate": 0.0,
"installment_amount": 5000.0,
"installments": 12,
"installment_start_date": "2025-01-01",
"apply_on": "end_of_month",
"settled": false,
"settled_date": null,
"asset_id": null,
"deduction_ids": [1,2,3]
}
}
]

View File

@@ -18,7 +18,8 @@ def employeeworkinformation_pre_save(sender, instance, **_kwargs):
instance.employee_id if instance.employee_id.is_active == True else None
)
if active_employee is not None:
contract_exists = active_employee.contract_set.exists()
all_contracts = Contract.objects.entire()
contract_exists = all_contracts.filter(employee_id_id=active_employee).exists()
if not contract_exists:
contract = Contract()
contract.contract_name = f"{active_employee}'s Contract"
@@ -50,12 +51,12 @@ def create_installments(sender, instance, created, **kwargs):
loan.amount = instance.loan_amount
loan.only_show_under_employee = True
loan.is_fixed = True
loan.is_fixed = True
loan.one_time_date = instance.provided_date
loan.is_loan = True
loan.save()
loan.include_active_employees = False
loan.specific_employees.add(instance.employee_id)
loan.save()
loan.specific_employees.add(instance.employee_id)
instance.allowance_id = loan
super(LoanAccount, instance).save()
else:

View File

@@ -246,10 +246,9 @@
});
});
// toggle columns //
toggleColumns("payslip_column_tab", "payslipCells")
toggleColumns("payslip-column-table", "payslipCells")
localStoragepayslipCells = localStorage.getItem("payslip_column_tab")
if (!localStoragepayslipCells) {
$("#payslipCells").find("[type=checkbox]").prop("checked", true)
}
$("[type=checkbox]").change()
</script>

View File

@@ -1,46 +1,52 @@
{% load i18n %}
<form
hx-post="{% url 'create-interview-schedule' %}"
hx-target="#createTarget"
hx-encoding="multipart/form-data"
id="skillform"
>
{% if messages %}
<script>
$('.filterButton')[0].click()
setTimeout(function () { $('.oh-modal__close').click(); }, 1000);
</script>
{% endif %}
<form hx-post="{% url 'create-interview-schedule' %}" hx-target="#createTarget" hx-encoding="multipart/form-data"
id="skillform">
{{form.as_p}}
</form>
<!-- <script>
$("#skillform .col-md-6").toggleClass("col-md-6");
$('[name=candidate_id]').change(function(){
$('[name=candidate_id]').change(function () {
var candidate_id = $('[name=candidate_id]').val();
var selectedmanagers = $('[name=employee_id]').val();
// Make AJAX request to fetch available Managers for the selected Candidate
$.ajax({
url: '{% url "get_managers" %}',
url: "{% url 'get_managers' %}",
method: 'GET',
data: {
'cand_id': candidate_id
'cand_id': candidate_id
},
success: function(data) {
// Clear existing options in the Managers dropdown
$('[name=employee_id]').empty();
success: function (data) {
// Clear existing options in the Managers dropdown
$('[name=employee_id]').empty();
// Append new options based on the response
$.each(data.employees, function(key, value) {
// Append new options based on the response
$.each(data.employees, function (key, value) {
$('[name=employee_id]').append($('<option>', {
value: key,
text: value
}));
$('[name=employee_id]').append($('<option>', {
value: key,
text: value
}));
});
});
// Set the selected Managers back to the dropdown
if (selectedmanagers) {
$('[name=employee_id]').val(selectedmanagers);
}
// Set the selected Managers back to the dropdown
if (selectedmanagers) {
$('[name=employee_id]').val(selectedmanagers);
}
}
});
});
<<<<<<< HEAD
</script> -->
=======
</script>
>>>>>>> a557b8a4c05c90515a575c7585620c822d2503d6

View File

@@ -2,26 +2,27 @@
{% include 'filter_tags.html' %}
{% if messages %}
<div class="oh-wrapper">
<div class="oh-wrapper">
{% for message in messages %}
<div class="oh-alert-container">
<div class="oh-alert oh-alert--animated {{message.tags}}">
{{ message }}
{{ message }}
</div>
</div>
{% endfor %}
</div>
</div>
{% endif %}
{% if data %}
{% if data %}
<div class="oh-card p-4">
<div class="oh-card__body">
<!-- start of column toggle button-->
<div class="oh-table_sticky--wrapper">
<div class="oh-sticky-dropdown--header">
<div class="oh-dropdown" x-data="{open: false}">
<button class="oh-sticky-dropdown_btn " @click="open = !open"><ion-icon name="ellipsis-vertical-sharp"
role="img" class="md hydrated" aria-label="ellipsis vertical sharp"></ion-icon></button>
<button class="oh-sticky-dropdown_btn " @click="open = !open"><ion-icon
name="ellipsis-vertical-sharp" role="img" class="md hydrated"
aria-label="ellipsis vertical sharp"></ion-icon></button>
<div class="oh-dropdown__menu oh-sticky-table_dropdown" x-show="open" @click.outside="open = false">
<ul class="oh-dropdown__items" id="interviewCells">
</ul>
@@ -38,67 +39,60 @@
<div class="oh-sticky-table__tr">
<div class="oh-sticky-table__th">{% trans "Candidate" %}</div>
<div data-cell-index="1" data-cell-title='{% trans "Interviewer" %}'
class="oh-sticky-table__th"
>{% trans "Interviewer" %}</div>
class="oh-sticky-table__th">{% trans "Interviewer" %}</div>
<div data-cell-index="2" data-cell-title='{% trans "Interview Date" %}'
class="oh-sticky-table__th {% if request.sort_option.order == '-interview_date' %}arrow-up {% elif request.sort_option.order == 'interview_date' %}arrow-down {% else %}arrow-up-down {% endif %}"
hx-get="{% url 'interview-filter-view' %}?{{pd}}&sortby=interview_date" hx-target="#section"
>{% trans "Interview Date" %}</div>
hx-get="{% url 'interview-filter-view' %}?{{pd}}&sortby=interview_date"
hx-target="#section">{% trans "Interview Date" %}</div>
<div data-cell-index="3" data-cell-title='{% trans "Interview Time" %}'
class="oh-sticky-table__th"
>{% trans "Interview Time" %}</div>
class="oh-sticky-table__th">{% trans "Interview Time" %}</div>
<div data-cell-index="4" data-cell-title='{% trans "Description" %}'
class="oh-sticky-table__th"
>{% trans "Description" %}</div>
<div data-cell-index="5" data-cell-title='{% trans "Status" %}'
class="oh-sticky-table__th"
>{% trans "Status" %}</div>
<div class="oh-sticky-table__th oh-sticky-table__right" align="center" style="width: 220px;">{% trans "Actions" %}</div>
class="oh-sticky-table__th">{% trans "Description" %}</div>
<div data-cell-index="5" data-cell-title='{% trans "Status" %}' class="oh-sticky-table__th">
{% trans "Status" %}</div>
<div class="oh-sticky-table__th oh-sticky-table__right" align="center"
style="width: 220px;">{% trans "Actions" %}</div>
</div>
</div>
<div class="oh-sticky-table__tbody">
{% for interview in data %}
<div class="oh-sticky-table__tr oh-permission-table__tr oh-permission-table--collapsed {% if request.user.employee_get in interview.employee_id.all %}diff-cell {% endif %}"
>
<div class="oh-sticky-table__sd oh-permission-table--toggle "
data-toggle-count
>
<div
class="oh-sticky-table__tr oh-permission-table__tr oh-permission-table--collapsed {% if request.user.employee_get in interview.employee_id.all %}diff-cell {% endif %}">
<div class="oh-sticky-table__sd oh-permission-table--toggle " data-toggle-count>
<div class="d-flex align-items-center">
<button class="oh-permission-table__collapse me-2">
<span title="{% trans "Reveal" %}"><ion-icon class="oh-permission-table__collapse-down" name="chevron-down-outline"></ion-icon></span>
<span title="{% trans "Collapse" %}"><ion-icon class="oh-permission-table__collapse-up" name="chevron-up-outline"></ion-icon></span>
<span title="{% trans " Reveal" %}"><ion-icon
class="oh-permission-table__collapse-down"
name="chevron-down-outline"></ion-icon></span>
<span title="{% trans " Collapse" %}"><ion-icon
class="oh-permission-table__collapse-up"
name="chevron-up-outline"></ion-icon></span>
</button>
<span class="oh-permission-table__user">{{interview.candidate_id}} </span>
</div>
</div>
<div data-cell-index="1" class="oh-sticky-table__td">
{% for employee in interview.employee_id.all %}
<div id="employeeContainer{{employee.id}}-{{interview.id}}">
<span class="oh-user-panel oh-collapse-panel" data-type="user" >
<div class="oh-profile oh-profile--md">
<div class="oh-profile__avatar mr-1">
<img
src="https://ui-avatars.com/api/?name={{employee.get_full_name}}&background=random"
class="oh-profile__image"
alt="Baby C."
/>
<div id="employeeContainer{{employee.id}}-{{interview.id}}">
<span class="oh-user-panel oh-collapse-panel" data-type="user">
<div class="oh-profile oh-profile--md">
<div class="oh-profile__avatar mr-1">
<img src="https://ui-avatars.com/api/?name={{employee.get_full_name}}&background=random"
class="oh-profile__image" alt="Baby C." />
</div>
<span class="oh-profile__name oh-text--dark"
title="{{employee.get_full_name}}">{{employee.get_full_name|truncatechars:15}}</span>
</div>
<span class="oh-profile__name oh-text--dark" title="{{employee.get_full_name}}"
>{{employee.get_full_name|truncatechars:15}}</span>
</div>
{% if perms.recruitment.change_interviewschedule or request.user.employee_get in interview.employee_id.all %}
<a
hx-confirm="{% trans 'Are you sure you want to remove this interviewer?' %}"
hx-post="{% url 'interview-employee-remove' interview.id employee.id %}"
title="{% trans "Remove" %}" hx-swap="outerHTML"
hx-target="#section"
onclick="event.stopPropagation()"
>
<ion-icon name="close-outline"></ion-icon>
</a>
{% endif %}
</span>
</div>
{% if perms.recruitment.change_interviewschedule or request.user.employee_get in interview.employee_id.all %}
<a hx-confirm="{% trans 'Are you sure you want to remove this interviewer?' %}"
hx-post="{% url 'interview-employee-remove' interview.id employee.id %}"
title="{% trans " Remove" %}" hx-swap="outerHTML" hx-target="#section"
onclick="event.stopPropagation()">
<ion-icon name="close-outline"></ion-icon>
</a>
{% endif %}
</span>
</div>
{% endfor %}
<span class="count-span">{{interview.employee_id.all|length}} {% trans "Interviewers" %}</span>
@@ -139,103 +133,94 @@
</div>
{% endif %}
</div>
<div class="oh-sticky-table__td oh-sticky-table__right">
<div class="oh-btn-group" onclick="event.stopPropagation()">
<div class="oh-sticky-table__td oh-sticky-table__right">
<div class="oh-btn-group" onclick="event.stopPropagation()">
{% if perms.recruitment.change_interviewschedule or request.user.employee_get in interview.employee_id.all %}
<a
title="{% trans "Edit" %}" hx-get="{% url 'edit-interview' interview.id %}?view=true"
{% if perms.recruitment.change_interviewschedule or request.user.employee_get in interview.employee_id.all %}
<a title="{% trans " Edit" %}"
hx-get="{% url 'edit-interview' interview.id %}?view=true"
data-target="#createModal" hx-swap="innerHTML" hx-target="#createTarget"
data-toggle="oh-modal-toggle" class="oh-btn oh-btn--light-bkg w-100"
><ion-icon name="create-outline"></ion-icon></a>
{% endif %}
data-toggle="oh-modal-toggle" class="oh-btn oh-btn--light-bkg w-100"><ion-icon
name="create-outline"></ion-icon></a>
{% endif %}
{% if perms.recruitment.delete_interviewschedule %}
<form
hx-post="{% url 'delete-interview' interview.id %}?view=true"
hx-target = "#section"
hx-confirm="{% trans "Are you sure you want to delete this interview?" %}"
method="post"
style="display: contents;width:100%">
{% csrf_token %}
<button onclick="event.stopPropagation()" type="submit" class="oh-btn oh-btn--light-bkg oh-btn--danger-outline w-100" title="{% trans 'Delete' %}">
<ion-icon name="trash-outline" role="img" class="md hydrated" aria-label="trash outline"></ion-icon>
</button>
</form>
{% endif %}
</div>
{% if perms.recruitment.delete_interviewschedule %}
<form hx-post="{% url 'delete-interview' interview.id %}?view=true"
hx-confirm="{% trans " Are you sure you want to delete this interview?" %}"
style="display: contents;width:100%">
{% csrf_token %}
<button onclick="event.stopPropagation()" type="submit"
class="oh-btn oh-btn--light-bkg oh-btn--danger-outline w-100"
title="{% trans 'Delete' %}">
<ion-icon name="trash-outline" role="img" class="md hydrated"
aria-label="trash outline"></ion-icon>
</button>
</form>
{% endif %}
</div>
</div>
</div>
{% endfor %}
</div>
</div>
<!-- end of sticky table -->
</div>
<!-- end of sticky table -->
</div>
</div>
<!-- start of pagination -->
<div class="oh-pagination">
<span class="oh-pagination__page">
{% trans "Page" %} {{ data.number }} {% trans "of" %} {{ data.paginator.num_pages }}.
</span>
<nav class="oh-pagination__nav">
<div class="oh-pagination__input-container me-3">
<span class="oh-pagination__label me-1">{% trans "Page" %}</span>
<input
type="number"
name="page"
class="oh-pagination__input"
value="{{data.number}}"
hx-get="{% url 'interview-filter-view' %}?{{pd}}"
hx-target="#section"
min="1"
/>
<span class="oh-pagination__label">{% trans "of" %} {{data.paginator.num_pages}}</span>
</div>
<ul class="oh-pagination__items">
{% if data.has_previous %}
<li class="oh-pagination__item oh-pagination__item--wide">
<a hx-target='#section' hx-get="{% url 'interview-filter-view' %}?{{pd}}&page=1" class="oh-pagination__link" onclick="tickCheckboxes();">{% trans "First" %}</a>
</li>
<li class="oh-pagination__item oh-pagination__item--wide">
<a hx-target='#section' hx-get="{% url 'interview-filter-view' %}?{{pd}}&page={{ data.previous_page_number }}" class="oh-pagination__link" onclick="tickCheckboxes();">{% trans "Previous" %}</a>
</li>
{% endif %}
{% if data.has_next %}
<li class="oh-pagination__item oh-pagination__item--wide">
<a hx-target='#section' hx-get="{% url 'interview-filter-view' %}?{{pd}}&page={{ data.next_page_number }}" class="oh-pagination__link" onclick="tickCheckboxes();">{% trans "Next" %}</a>
</li>
<li class="oh-pagination__item oh-pagination__item--wide">
<a hx-target='#section' hx-get="{% url 'interview-filter-view' %}?{{pd}}&page={{ data.paginator.num_pages }}" class="oh-pagination__link" onclick="tickCheckboxes();">{% trans "Last" %}</a>
</li>
{% endif %}
</ul>
</nav>
</div>
</div>
{% else %}
<div style="
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
"
>
<span class="material-symbols-outlined" style="font-size: 190px;">
groups
</span>
<h5 class="oh-404__subtitle">{% trans "No Interviews Found." %}</h5>
</div>
{% endif %}
<script>
// toggle columns //
toggleColumns("interview-table", "interviewCells");
localStorageinterviewCells = localStorage.getItem(
"interview_table"
);
if (!localStorageinterviewCells) {
$("#interviewCells").find("[type=checkbox]").prop("checked", true);
}
$("[type=checkbox]").change();
</script>
<div class="oh-pagination">
<span class="oh-pagination__page">
{% trans "Page" %} {{ data.number }} {% trans "of" %} {{ data.paginator.num_pages }}.
</span>
<nav class="oh-pagination__nav">
<div class="oh-pagination__input-container me-3">
<span class="oh-pagination__label me-1">{% trans "Page" %}</span>
<input type="number" name="page" class="oh-pagination__input" value="{{data.number}}"
hx-get="{% url 'interview-filter-view' %}?{{pd}}" hx-target="#section" min="1" />
<span class="oh-pagination__label">{% trans "of" %} {{data.paginator.num_pages}}</span>
</div>
<ul class="oh-pagination__items">
{% if data.has_previous %}
<li class="oh-pagination__item oh-pagination__item--wide">
<a hx-target='#section' hx-get="{% url 'interview-filter-view' %}?{{pd}}&page=1"
class="oh-pagination__link" onclick="tickCheckboxes();">{% trans "First" %}</a>
</li>
<li class="oh-pagination__item oh-pagination__item--wide">
<a hx-target='#section'
hx-get="{% url 'interview-filter-view' %}?{{pd}}&page={{ data.previous_page_number }}"
class="oh-pagination__link" onclick="tickCheckboxes();">{% trans "Previous" %}</a>
</li>
{% endif %}
{% if data.has_next %}
<li class="oh-pagination__item oh-pagination__item--wide">
<a hx-target='#section'
hx-get="{% url 'interview-filter-view' %}?{{pd}}&page={{ data.next_page_number }}"
class="oh-pagination__link" onclick="tickCheckboxes();">{% trans "Next" %}</a>
</li>
<li class="oh-pagination__item oh-pagination__item--wide">
<a hx-target='#section'
hx-get="{% url 'interview-filter-view' %}?{{pd}}&page={{ data.paginator.num_pages }}"
class="oh-pagination__link" onclick="tickCheckboxes();">{% trans "Last" %}</a>
</li>
{% endif %}
</ul>
</nav>
</div>
{% else %}
<div class="oh-404">
<span class="material-symbols-outlined" style="font-size: 190px;">
groups
</span>
<h5 class="oh-404__subtitle">{% trans "No Interviews Found." %}</h5>
</div>
{% endif %}
<script>
// toggle columns //
toggleColumns("interview-table", "interviewCells");
localStorageinterviewCells = localStorage.getItem(
"interview_table"
);
if (!localStorageinterviewCells) {
$("#interviewCells").find("[type=checkbox]").prop("checked", true);
}
</script>

View File

@@ -29,7 +29,7 @@
</style>
{% include 'candidate/interview_nav.html' %}
<div class="oh-wrapper">
<div id="section" hx-target="#section" hx-swap="innerHTML">
<div id="section">
{% include 'candidate/interview_list.html' %}
</div>
</div>

View File

@@ -104,8 +104,8 @@ def dashboard(request):
if stage_chart_count >= 1:
stage_chart_count = 1
onboarding_count = Candidate.objects.filter(start_onboard=True)
onboarding_count = onboarding_count.count()
accepted = Candidate.objects.filter(offer_letter_status="accepted")
accepted_count = accepted.count()
recruitment_manager_mapping = {}
@@ -139,7 +139,7 @@ def dashboard(request):
hired_ratio = f"{((total_hired_candidates / total_vacancy) * 100):.1f}"
total_candidate_ratio = f"{((total_candidates / total_vacancy) * 100):.1f}"
if total_hired_candidates != 0:
acceptance_ratio = f"{((onboarding_count / total_hired_candidates) * 100):.1f}"
acceptance_ratio = f"{((accepted_count / total_hired_candidates) * 100):.1f}"
skill_zone = SkillZone.objects.filter(is_active=True)
return render(

View File

@@ -1398,7 +1398,7 @@ def interview_filter_view(request):
previous_data = request.GET.urlencode()
if request.user.has_perm("view_interviewschedule"):
if request.user.has_perm("recruitment.view_interviewschedule"):
interviews = InterviewSchedule.objects.all().order_by("-interview_date")
else:
interviews = InterviewSchedule.objects.filter(
@@ -1434,7 +1434,7 @@ def interview_view(request):
"""
previous_data = request.GET.urlencode()
if request.user.has_perm("view_interviewschedule"):
if request.user.has_perm("recruitment.view_interviewschedule"):
interviews = InterviewSchedule.objects.all().order_by("-interview_date")
else:
interviews = InterviewSchedule.objects.filter(
@@ -2035,7 +2035,6 @@ def create_interview_schedule(request):
)
messages.success(request, "Interview Scheduled successfully.")
return HttpResponse("<script>window.location.reload()</script>")
return render(request, template, {"form": form})
@@ -2044,21 +2043,23 @@ def create_interview_schedule(request):
@manager_can_enter(perm="recruitment.delete_interviewschedule")
def interview_delete(request, interview_id):
"""
This method is used to delete interview
Deletes an interview schedule.
Args:
interview_id : interview schedule instance id
interview_id: InterviewSchedule instance ID
"""
view = request.GET.get("view", "false")
view = request.GET.get("view")
interview = InterviewSchedule.objects.get(id=interview_id)
interview.delete()
messages.success(request, "Interview deleted successfully.")
if view == "true":
# return HttpResponse("<script>window.location.reload()</script>")
return redirect(reverse("interview-list-view"))
else:
# return redirect(reverse("interview-detail-view", kwargs={'pk': interview_id}))
return HttpResponse("<script>window.location.reload()</script>")
try:
InterviewSchedule.objects.get(id=interview_id).delete()
messages.success(request, _("Interview deleted successfully."))
except:
messages.error(request, _("Scheduled Interview not found"))
return HttpResponse(
"<script>$('.filterButton')[0].click()</script>"
if view == "true"
else "<script>window.location.reload()</script>"
)
@login_required

View File

@@ -601,3 +601,16 @@ form label {
border: solid 1px;
border-radius: 5px;
}
#c {
position: absolute;
top: 0;
left: 0;
width: 100%;
/* Make sure the canvas fills the modal */
height: 100%;
z-index: 1000;
/* Ensure it's above the blurred background */
pointer-events: none;
/* Ensure clicks pass through to underlying content */
}

View File

@@ -105,15 +105,6 @@
z-index: 1000; /* Ensure it's behind the canvas */
}
#c {
position: absolute;
top: 0;
left: 0;
width: 100%; /* Make sure the canvas fills the modal */
height: 100%;
z-index: 1000; /* Ensure it's above the blurred background */
pointer-events: none; /* Ensure clicks pass through to underlying content */
}
</style>
@@ -153,12 +144,6 @@
<!-- end of back button -->
<div class="oh-dashboard row" id="dashboard" style="padding-bottom: 3.5rem;">
{% if is_birthday %}
<div class="page-wrapper">
<div class="blurred-background"></div>
<canvas id="c"></canvas>
</div>
{% endif %}
<div class="oh-dashboard__left col-12 col-sm-12 col-md-12 col-lg-9">
<div class="oh-dashboard__cards row">

View File

@@ -67,6 +67,12 @@
{% endfor %}
</div>
{% endif %}
{% if is_birthday %}
<div class="page-wrapper">
<div class="blurred-background"></div>
<canvas id="c"></canvas>
</div>
{% endif %}
<button id="reloadMessagesButton" hx-get="{% url 'reload-messages' %}" hx-swap="afterend" hidden hx-target="#reloadMessages"></button>
{% include "generic/components.html" %}