Pylint updates

This commit is contained in:
Horilla
2025-05-20 14:14:53 +05:30
parent 0b327c4923
commit 3f77c65a4c
23 changed files with 1494 additions and 800 deletions

View File

@@ -2,17 +2,18 @@ from django.apps import AppConfig
class ReportConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'report'
default_auto_field = "django.db.models.BigAutoField"
name = "report"
def ready(self) -> None:
ready = super().ready()
from django.urls import include, path
from horilla.urls import urlpatterns
from horilla.horilla_settings import APPS
from horilla.urls import urlpatterns
urlpatterns.append(
path("report/", include("report.urls")),
)
return ready
return ready

View File

@@ -1,90 +1,119 @@
from django.utils.translation import gettext_lazy as trans
from django.urls import reverse_lazy
from django.apps import apps
from django.urls import reverse_lazy
from django.utils.translation import gettext_lazy as trans
MENU = trans("Reports")
IMG_SRC = "images/ui/report.svg"
ACCESSIBILITY = "report.sidebar.menu_accessibility"
SUBMENUS = [
]
SUBMENUS = []
# Dynamically adding submenu if the app is installed
if apps.is_installed('recruitment'):
SUBMENUS.append({
"menu": "Recruitment",
"redirect": reverse_lazy("recruitment-report"),
"accessibility": "report.sidebar.recruitment_accessibility",
})
if apps.is_installed("recruitment"):
SUBMENUS.append(
{
"menu": "Recruitment",
"redirect": reverse_lazy("recruitment-report"),
"accessibility": "report.sidebar.recruitment_accessibility",
}
)
if apps.is_installed('employee'):
SUBMENUS.append({
"menu":"Employee",
"redirect":reverse_lazy("employee-report"),
"accessibility": "report.sidebar.employee_accessibility",
})
if apps.is_installed("employee"):
SUBMENUS.append(
{
"menu": "Employee",
"redirect": reverse_lazy("employee-report"),
"accessibility": "report.sidebar.employee_accessibility",
}
)
if apps.is_installed('attendance'):
SUBMENUS.append({
"menu":"Attendance",
"redirect":reverse_lazy("attendance-report"),
"accessibility": "report.sidebar.attendance_accessibility",
})
if apps.is_installed("attendance"):
SUBMENUS.append(
{
"menu": "Attendance",
"redirect": reverse_lazy("attendance-report"),
"accessibility": "report.sidebar.attendance_accessibility",
}
)
if apps.is_installed('leave'):
SUBMENUS.append({
"menu":"Leave",
"redirect":reverse_lazy("leave-report"),
"accessibility": "report.sidebar.leave_accessibility",
})
if apps.is_installed("leave"):
SUBMENUS.append(
{
"menu": "Leave",
"redirect": reverse_lazy("leave-report"),
"accessibility": "report.sidebar.leave_accessibility",
}
)
if apps.is_installed('payroll'):
SUBMENUS.append({
"menu":"Payroll",
"redirect":reverse_lazy("payroll-report"),
"accessibility": "report.sidebar.payroll_accessibility",
})
if apps.is_installed("payroll"):
SUBMENUS.append(
{
"menu": "Payroll",
"redirect": reverse_lazy("payroll-report"),
"accessibility": "report.sidebar.payroll_accessibility",
}
)
if apps.is_installed('asset'):
SUBMENUS.append({
"menu":"Asset",
"redirect":reverse_lazy("asset-report"),
"accessibility": "report.sidebar.asset_accessibility",
})
if apps.is_installed("asset"):
SUBMENUS.append(
{
"menu": "Asset",
"redirect": reverse_lazy("asset-report"),
"accessibility": "report.sidebar.asset_accessibility",
}
)
if apps.is_installed("pms"):
SUBMENUS.append(
{
"menu": "Performance",
"redirect": reverse_lazy("pms-report"),
"accessibility": "report.sidebar.pms_accessibility",
}
)
if apps.is_installed('pms'):
SUBMENUS.append({
"menu":"Performance",
"redirect":reverse_lazy("pms-report"),
"accessibility": "report.sidebar.pms_accessibility",
})
def menu_accessibility(request, submenu, user_perms, *args, **kwargs):
return request.user.is_superuser or request.user.has_perm("recruitment.view_recruitment") or request.user.has_perm("employee.view_employee") or request.user.has_perm("pms.view_objective") or request.user.has_perm("attendance.view_attendance") or request.user.has_perm("leave.view_leaverequest") or request.user.has_perm("payroll.view_payslip") or request.user.has_perm("asset.view_asset")
return (
request.user.is_superuser
or request.user.has_perm("recruitment.view_recruitment")
or request.user.has_perm("employee.view_employee")
or request.user.has_perm("pms.view_objective")
or request.user.has_perm("attendance.view_attendance")
or request.user.has_perm("leave.view_leaverequest")
or request.user.has_perm("payroll.view_payslip")
or request.user.has_perm("asset.view_asset")
)
def recruitment_accessibility(request, submenu, user_perms, *args, **kwargs):
return request.user.is_superuser or request.user.has_perm("recruitment.view_recruitment")
return request.user.is_superuser or request.user.has_perm(
"recruitment.view_recruitment"
)
def employee_accessibility(request, submenu, user_perms, *args, **kwargs):
return request.user.is_superuser or request.user.has_perm("employee.view_employee")
def attendance_accessibility(request, submenu, user_perms, *args, **kwargs):
return request.user.is_superuser or request.user.has_perm("attendance.view_attendance")
return request.user.is_superuser or request.user.has_perm(
"attendance.view_attendance"
)
def leave_accessibility(request, submenu, user_perms, *args, **kwargs):
return request.user.is_superuser or request.user.has_perm("leave.view_leaverequest")
def payroll_accessibility(request, submenu, user_perms, *args, **kwargs):
return request.user.is_superuser or request.user.has_perm("payroll.view_payslip")
def asset_accessibility(request, submenu, user_perms, *args, **kwargs):
return request.user.is_superuser or request.user.has_perm("asset.view_asset")
def pms_accessibility(request, submenu, user_perms, *args, **kwargs):
return request.user.is_superuser or request.user.has_perm("pms.view_objective")

View File

@@ -13,7 +13,7 @@
<h1 class="oh-main__titlebar-title fw-bold">
{% trans "Asset Reports" %}
</h1>
<div style="display:inline-flex;">
<!-- Filter section -->
@@ -51,7 +51,7 @@
<label class="oh-label" for="{{asset_filter_form.asset_tracking_id.id_for_label}}">{% trans "Tracking Id" %}</label>
{{asset_filter_form.asset_tracking_id}}
</div>
</div>
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
@@ -136,7 +136,7 @@
rendererName: "Table", // Default view as Table
onRefresh: function (config) {
let currentRenderer = config.rendererName;
if (currentRenderer === "Table" || currentRenderer === "Table Barchart" ||
if (currentRenderer === "Table" || currentRenderer === "Table Barchart" ||
currentRenderer === "Heatmap" || currentRenderer === "Row Heatmap" || currentRenderer === "Col Heatmap" ) {
$("#export-btn").show(); // Show button for tables
} else {
@@ -165,7 +165,7 @@
rendererName: "Table", // Default view as Table
onRefresh: function (config) {
let currentRenderer = config.rendererName;
if (currentRenderer === "Table" || currentRenderer === "Table Barchart" ||
if (currentRenderer === "Table" || currentRenderer === "Table Barchart" ||
currentRenderer === "Heatmap" || currentRenderer === "Row Heatmap" || currentRenderer === "Col Heatmap" ) {
$("#export-btn").show(); // Show button for tables
} else {
@@ -198,7 +198,7 @@
alert("No table found to export.");
return;
}
const workbook = new ExcelJS.Workbook();
const worksheet = workbook.addWorksheet("Pivot Data");
const baseRow = 5;
@@ -215,7 +215,7 @@
city: "{{ company.city|escapejs }}",
zip: "{{ company.zip|escapejs }}"
};
function getBase64FromUrl(url) {
return fetch(url)
.then(response => response.blob())
@@ -226,7 +226,7 @@
reader.readAsDataURL(blob);
}));
}
const logoUrl = "{{ protocol }}://{{ host }}{{ company.icon.url }}";
await getBase64FromUrl(logoUrl).then((base64) => {
const base64Data = base64.split(',')[1];
@@ -234,13 +234,13 @@
base64: base64Data,
extension: 'png'
});
worksheet.addImage(imageId, {
tl: { col: baseCol - 1, row: currentRow - 1 },
ext: { width: 80, height: 80 }
});
});
// Merge cells for company details text
const companyTextCell = worksheet.getCell(currentRow, baseCol + 1);
worksheet.mergeCells(currentRow, baseCol + 1, currentRow, baseCol + 2);
@@ -258,46 +258,46 @@
wrapText: true
};
worksheet.getRow(currentRow).height = 80;
currentRow += 2; // Leave a blank row
}
// Add timestamp
const timestamp = new Date().toLocaleDateString('en-GB') + ' ' +
new Date().toLocaleTimeString('en-US', {
hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: true
});
const downloadCell = worksheet.getCell(currentRow, baseCol);
worksheet.mergeCells(currentRow, baseCol, currentRow, baseCol + 3);
downloadCell.value = `Generated on: ${timestamp}`;
downloadCell.alignment = { horizontal: 'left', vertical: 'middle', wrapText: true };
downloadCell.font = { size: 10, italic: true, color: { argb: 'FF666666' }, bold: true };
currentRow += 3;
// Table rendering
const cellMap = {};
const allRows = Array.from(table.rows);
const lastRowIndex = allRows.length - 1;
allRows.forEach((row, rowIndex) => {
let colIndex = baseCol;
Array.from(row.cells).forEach((cell) => {
while (cellMap[`${currentRow + rowIndex}-${colIndex}`]) {
colIndex++;
}
const rowspan = parseInt(cell.getAttribute("rowspan")) || 1;
const colspan = parseInt(cell.getAttribute("colspan")) || 1;
const cellValue = cell.textContent.trim();
const excelCell = worksheet.getCell(currentRow + rowIndex, colIndex);
excelCell.value = cellValue;
const isHeader = rowIndex === 0;
const isLastRow = rowIndex === lastRowIndex;
@@ -328,7 +328,7 @@
right: { style: 'thin' }
};
excelCell.alignment = { horizontal: "center", vertical: "middle" };
if (rowspan > 1 || colspan > 1) {
worksheet.mergeCells(
currentRow + rowIndex,
@@ -336,7 +336,7 @@
currentRow + rowIndex + rowspan - 1,
colIndex + colspan - 1
);
for (let r = 0; r < rowspan; r++) {
for (let c = 0; c < colspan; c++) {
cellMap[`${currentRow + rowIndex + r}-${colIndex + c}`] = true;
@@ -345,15 +345,15 @@
} else {
cellMap[`${currentRow + rowIndex}-${colIndex}`] = true;
}
colIndex++;
});
});
worksheet.getRow(currentRow + lastRowIndex).height = 25; // adjust height for Total
worksheet.getRow(currentRow).height = 30; // adjust height for Heading
worksheet.columns.forEach(column => {
let maxLength = 2;
column.eachCell({ includeEmpty: true }, cell => {
@@ -362,13 +362,13 @@
});
column.width = maxLength + 3;
});
const buffer = await workbook.xlsx.writeBuffer();
const blob = new Blob([buffer], {
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
});
const link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.download = filename;

View File

@@ -11,7 +11,7 @@
<h1 class="oh-main__titlebar-title fw-bold">
{% trans "Attendance Reports" %}
</h1>
<div style="display:inline-flex;">
<!-- Filter section -->
@@ -213,7 +213,7 @@
$.pivotUtilities.renderers,
plotlyRenderers // Adding Plotly renderers
),
// Hide specific fields from selection dropdown
onRefresh: function (config) {
let currentRenderer = config.rendererName;
@@ -284,7 +284,7 @@
$.pivotUtilities.renderers,
plotlyRenderers // Adding Plotly renderers
),
// Hide specific fields from selection dropdown
onRefresh: function (config) {
let currentRenderer = config.rendererName;
@@ -319,7 +319,7 @@
}, 10);
}
});
});
// When the filter form is submitted, prevent default action and load filtered data
@@ -341,7 +341,7 @@
alert("No table found to export.");
return;
}
const workbook = new ExcelJS.Workbook();
const worksheet = workbook.addWorksheet("Pivot Data");
const baseRow = 5;
@@ -358,7 +358,7 @@
city: "{{ company.city|escapejs }}",
zip: "{{ company.zip|escapejs }}"
};
function getBase64FromUrl(url) {
return fetch(url)
.then(response => response.blob())
@@ -369,7 +369,7 @@
reader.readAsDataURL(blob);
}));
}
const logoUrl = "{{ protocol }}://{{ host }}{{ company.icon.url }}";
await getBase64FromUrl(logoUrl).then((base64) => {
const base64Data = base64.split(',')[1];
@@ -377,13 +377,13 @@
base64: base64Data,
extension: 'png'
});
worksheet.addImage(imageId, {
tl: { col: baseCol - 1, row: currentRow - 1 },
ext: { width: 80, height: 80 }
});
});
// Merge cells for company details text
const companyTextCell = worksheet.getCell(currentRow, baseCol + 1);
worksheet.mergeCells(currentRow, baseCol + 1, currentRow, baseCol + 2);
@@ -401,46 +401,46 @@
wrapText: true
};
worksheet.getRow(currentRow).height = 80;
currentRow += 2; // Leave a blank row
}
// Add timestamp
const timestamp = new Date().toLocaleDateString('en-GB') + ' ' +
new Date().toLocaleTimeString('en-US', {
hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: true
});
const downloadCell = worksheet.getCell(currentRow, baseCol);
worksheet.mergeCells(currentRow, baseCol, currentRow, baseCol + 3);
downloadCell.value = `Generated on: ${timestamp}`;
downloadCell.alignment = { horizontal: 'left', vertical: 'middle', wrapText: true };
downloadCell.font = { size: 10, italic: true, color: { argb: 'FF666666' }, bold: true };
currentRow += 3;
// Table rendering
const cellMap = {};
const allRows = Array.from(table.rows);
const lastRowIndex = allRows.length - 1;
allRows.forEach((row, rowIndex) => {
let colIndex = baseCol;
Array.from(row.cells).forEach((cell) => {
while (cellMap[`${currentRow + rowIndex}-${colIndex}`]) {
colIndex++;
}
const rowspan = parseInt(cell.getAttribute("rowspan")) || 1;
const colspan = parseInt(cell.getAttribute("colspan")) || 1;
const cellValue = cell.textContent.trim();
const excelCell = worksheet.getCell(currentRow + rowIndex, colIndex);
excelCell.value = cellValue;
const isHeader = rowIndex === 0;
const isLastRow = rowIndex === lastRowIndex;
@@ -471,7 +471,7 @@
right: { style: 'thin' }
};
excelCell.alignment = { horizontal: "center", vertical: "middle" };
if (rowspan > 1 || colspan > 1) {
worksheet.mergeCells(
currentRow + rowIndex,
@@ -479,7 +479,7 @@
currentRow + rowIndex + rowspan - 1,
colIndex + colspan - 1
);
for (let r = 0; r < rowspan; r++) {
for (let c = 0; c < colspan; c++) {
cellMap[`${currentRow + rowIndex + r}-${colIndex + c}`] = true;
@@ -488,15 +488,15 @@
} else {
cellMap[`${currentRow + rowIndex}-${colIndex}`] = true;
}
colIndex++;
});
});
worksheet.getRow(currentRow + lastRowIndex).height = 25; // adjust height for Total
worksheet.getRow(currentRow).height = 30; // adjust height for Heading
worksheet.columns.forEach(column => {
let maxLength = 2;
column.eachCell({ includeEmpty: true }, cell => {
@@ -505,13 +505,13 @@
});
column.width = maxLength + 3;
});
const buffer = await workbook.xlsx.writeBuffer();
const blob = new Blob([buffer], {
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
});
const link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.download = filename;

View File

@@ -51,7 +51,7 @@
<label class="oh-label" for="{{f.form.country.id_for_label}}">{% trans "Country" %}</label>
{{f.form.country}}
</div>
</div>
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
@@ -162,7 +162,7 @@
rendererName: "Table", // Default view as Table
onRefresh: function (config) {
let currentRenderer = config.rendererName;
if (currentRenderer === "Table" || currentRenderer === "Table Barchart" ||
if (currentRenderer === "Table" || currentRenderer === "Table Barchart" ||
currentRenderer === "Heatmap" || currentRenderer === "Row Heatmap" || currentRenderer === "Col Heatmap" ) {
$("#export-btn").show(); // Show button for tables
} else {
@@ -196,7 +196,7 @@
rendererName: "Table", // Default view as Table
onRefresh: function (config) {
let currentRenderer = config.rendererName;
if (currentRenderer === "Table" || currentRenderer === "Table Barchart" ||
if (currentRenderer === "Table" || currentRenderer === "Table Barchart" ||
currentRenderer === "Heatmap" || currentRenderer === "Row Heatmap" || currentRenderer === "Col Heatmap" ) {
$("#export-btn").show(); // Show button for tables
} else {
@@ -208,7 +208,7 @@
plotlyRenderers // Adding Plotly renderers
)
});
});
// When the filter form is submitted, prevent default action and load filtered data
@@ -230,7 +230,7 @@
alert("No table found to export.");
return;
}
const workbook = new ExcelJS.Workbook();
const worksheet = workbook.addWorksheet("Pivot Data");
const baseRow = 5;
@@ -247,7 +247,7 @@
city: "{{ company.city|escapejs }}",
zip: "{{ company.zip|escapejs }}"
};
function getBase64FromUrl(url) {
return fetch(url)
.then(response => response.blob())
@@ -258,7 +258,7 @@
reader.readAsDataURL(blob);
}));
}
const logoUrl = "{{ protocol }}://{{ host }}{{ company.icon.url }}";
await getBase64FromUrl(logoUrl).then((base64) => {
const base64Data = base64.split(',')[1];
@@ -266,13 +266,13 @@
base64: base64Data,
extension: 'png'
});
worksheet.addImage(imageId, {
tl: { col: baseCol - 1, row: currentRow - 1 },
ext: { width: 80, height: 80 }
});
});
// Merge cells for company details text
const companyTextCell = worksheet.getCell(currentRow, baseCol + 1);
worksheet.mergeCells(currentRow, baseCol + 1, currentRow, baseCol + 2);
@@ -290,46 +290,46 @@
wrapText: true
};
worksheet.getRow(currentRow).height = 80;
currentRow += 2; // Leave a blank row
}
// Add timestamp
const timestamp = new Date().toLocaleDateString('en-GB') + ' ' +
new Date().toLocaleTimeString('en-US', {
hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: true
});
const downloadCell = worksheet.getCell(currentRow, baseCol);
worksheet.mergeCells(currentRow, baseCol, currentRow, baseCol + 3);
downloadCell.value = `Generated on: ${timestamp}`;
downloadCell.alignment = { horizontal: 'left', vertical: 'middle', wrapText: true };
downloadCell.font = { size: 10, italic: true, color: { argb: 'FF666666' }, bold: true };
currentRow += 3;
// Table rendering
const cellMap = {};
const allRows = Array.from(table.rows);
const lastRowIndex = allRows.length - 1;
allRows.forEach((row, rowIndex) => {
let colIndex = baseCol;
Array.from(row.cells).forEach((cell) => {
while (cellMap[`${currentRow + rowIndex}-${colIndex}`]) {
colIndex++;
}
const rowspan = parseInt(cell.getAttribute("rowspan")) || 1;
const colspan = parseInt(cell.getAttribute("colspan")) || 1;
const cellValue = cell.textContent.trim();
const excelCell = worksheet.getCell(currentRow + rowIndex, colIndex);
excelCell.value = cellValue;
const isHeader = rowIndex === 0;
const isLastRow = rowIndex === lastRowIndex;
@@ -360,7 +360,7 @@
right: { style: 'thin' }
};
excelCell.alignment = { horizontal: "center", vertical: "middle" };
if (rowspan > 1 || colspan > 1) {
worksheet.mergeCells(
currentRow + rowIndex,
@@ -368,7 +368,7 @@
currentRow + rowIndex + rowspan - 1,
colIndex + colspan - 1
);
for (let r = 0; r < rowspan; r++) {
for (let c = 0; c < colspan; c++) {
cellMap[`${currentRow + rowIndex + r}-${colIndex + c}`] = true;
@@ -377,15 +377,15 @@
} else {
cellMap[`${currentRow + rowIndex}-${colIndex}`] = true;
}
colIndex++;
});
});
worksheet.getRow(currentRow + lastRowIndex).height = 25; // adjust height for Total
worksheet.getRow(currentRow).height = 30; // adjust height for Heading
worksheet.columns.forEach(column => {
let maxLength = 2;
column.eachCell({ includeEmpty: true }, cell => {
@@ -394,13 +394,13 @@
});
column.width = maxLength + 3;
});
const buffer = await workbook.xlsx.writeBuffer();
const blob = new Blob([buffer], {
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
});
const link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.download = filename;

View File

@@ -12,7 +12,7 @@
{% trans "Leave Reports" %}
</h1>
<div style="display:inline-flex;">
<!-- Filter section -->
<form id="filterForm" onsubmit="event.preventDefault(); loadFilteredPivotData();" class="me-3" style="margin-top: 10px;">
@@ -78,7 +78,7 @@
{{form.from_date}}
</div>
</div>
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<label class="oh-label" for="{{ form.to_date.id_for_label }}">{% trans "To Date" %}</label>
@@ -292,17 +292,17 @@
containerId = "pivot-availableleave";
rowsConfig = ["Name","Department", "Leave Type","Assigned Date","Total Leave Days","Available Days","Carryforward Days"]
}
// Show relevant container
$("#" + containerId).show();
// Fetch data dynamically based on model
$.getJSON(url, function (data) {
// Add Plotly renderers correctly
let plotlyRenderers = $.pivotUtilities.plotly_renderers;
// Initialize pivot table with Plotly enabled
$("#" + containerId).pivotUI(data, {
rows: rowsConfig,
@@ -331,12 +331,12 @@
window.loadFilteredPivotData =function loadFilteredPivotData() {
const selectedModel = $("#model-select").val();
const formData = $("#filterForm").serialize();
$(".pivot-wrapper").hide();
let containerId = "";
let rowsConfig = [];
if (selectedModel === "leave_request"){
containerId = "pivot-leave";
rowsConfig = ["Name","Department","Shift", "Leave Type","Requested Days","Start Date","End Date","Status"]
@@ -344,13 +344,13 @@
containerId = "pivot-availableleave";
rowsConfig = ["Name","Department", "Leave Type","Assigned Date","Total Leave Days","Available Days","Carryforward Days"]
}
$("#" + containerId).show();
$.getJSON(`leave-pivot?model=${selectedModel}&${formData}`, function (data) {
const plotlyRenderers = $.pivotUtilities.plotly_renderers;
$("#" + containerId).pivotUI(data, {
rows: rowsConfig,
cols: [],
@@ -364,21 +364,21 @@
} else {
$("#export-btn").hide();
}
}
});
});
}
// Initial load with all models
loadPivotData("leave_request");
// Model selection change event
$("#model-select").on("change", function () {
let selectedModel = $(this).val();
loadPivotData(selectedModel); // Reload pivot data with selected model
});
// Export to Excel on button click
$("#export-btn").on("click", function () {
let visiblePivot = $(".pivot-wrapper:visible .pvtTable").closest(".pivot-wrapper");
@@ -397,14 +397,14 @@
alert("No table found to export.");
return;
}
const workbook = new ExcelJS.Workbook();
const worksheet = workbook.addWorksheet("Pivot Data");
const baseRow = 5;
const baseCol = 5;
let currentRow = baseRow;
// Add company details first (if not 'all')
if ('{{company}}' !== 'all') {
const companyDetails = {
@@ -415,7 +415,7 @@
city: "{{ company.city|escapejs }}",
zip: "{{ company.zip|escapejs }}"
};
function getBase64FromUrl(url) {
return fetch(url)
.then(response => response.blob())
@@ -426,7 +426,7 @@
reader.readAsDataURL(blob);
}));
}
const logoUrl = "{{ protocol }}://{{ host }}{{ company.icon.url }}";
await getBase64FromUrl(logoUrl).then((base64) => {
const base64Data = base64.split(',')[1];
@@ -434,13 +434,13 @@
base64: base64Data,
extension: 'png'
});
worksheet.addImage(imageId, {
tl: { col: baseCol - 1, row: currentRow - 1 },
ext: { width: 80, height: 80 }
});
});
// Merge cells for company details text
const companyTextCell = worksheet.getCell(currentRow, baseCol + 1);
worksheet.mergeCells(currentRow, baseCol + 1, currentRow, baseCol + 2);
@@ -458,51 +458,51 @@
wrapText: true
};
worksheet.getRow(currentRow).height = 80;
currentRow += 2; // Leave a blank row
}
// Add timestamp
const timestamp = new Date().toLocaleDateString('en-GB') + ' ' +
new Date().toLocaleTimeString('en-US', {
hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: true
});
const downloadCell = worksheet.getCell(currentRow, baseCol);
worksheet.mergeCells(currentRow, baseCol, currentRow, baseCol + 3);
downloadCell.value = `Generated on: ${timestamp}`;
downloadCell.alignment = { horizontal: 'left', vertical: 'middle', wrapText: true };
downloadCell.font = { size: 10, italic: true, color: { argb: 'FF666666' }, bold: true };
currentRow += 3; // Leave some rows before the table
// ------------------------
// Render pivot table
// ------------------------
const cellMap = {};
const allRows = Array.from(table.rows);
const lastRowIndex = allRows.length - 1;
allRows.forEach((row, rowIndex) => {
let colIndex = baseCol;
Array.from(row.cells).forEach((cell) => {
while (cellMap[`${currentRow + rowIndex}-${colIndex}`]) {
colIndex++;
}
const rowspan = parseInt(cell.getAttribute("rowspan")) || 1;
const colspan = parseInt(cell.getAttribute("colspan")) || 1;
const cellValue = cell.textContent.trim();
const excelCell = worksheet.getCell(currentRow + rowIndex, colIndex);
excelCell.value = cellValue;
const isHeader = rowIndex === 0;
const isLastRow = rowIndex === lastRowIndex;
excelCell.font = {
bold: isHeader || isLastRow,
size: isHeader ? 12 : 11,
@@ -512,7 +512,7 @@
'FF000000'
}
};
excelCell.fill = {
type: 'pattern',
pattern: 'solid',
@@ -530,7 +530,7 @@
right: { style: 'thin' }
};
excelCell.alignment = { horizontal: "center", vertical: "middle" };
// Merge
if (rowspan > 1 || colspan > 1) {
worksheet.mergeCells(
@@ -539,7 +539,7 @@
currentRow + rowIndex + rowspan - 1,
colIndex + colspan - 1
);
for (let r = 0; r < rowspan; r++) {
for (let c = 0; c < colspan; c++) {
cellMap[`${currentRow + rowIndex + r}-${colIndex + c}`] = true;
@@ -548,15 +548,15 @@
} else {
cellMap[`${currentRow + rowIndex}-${colIndex}`] = true;
}
colIndex++;
});
});
worksheet.getRow(currentRow + lastRowIndex).height = 25; // adjust height for Total
worksheet.getRow(currentRow).height = 30; // adjust height for Heading
// Auto-adjust column widths
worksheet.columns.forEach(column => {
let maxLength = 2;
@@ -566,13 +566,13 @@
});
column.width = maxLength + 3;
});
// Save
const buffer = await workbook.xlsx.writeBuffer();
const blob = new Blob([buffer], {
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
});
const link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.download = filename;
@@ -580,7 +580,7 @@
}
});
</script>

View File

@@ -62,8 +62,8 @@
</div>
</div>
</div>
<div class="row">
<div class="col-sm-6">
@@ -208,7 +208,7 @@
</div>
</div>
</div>
</div>
</div>
</div>
@@ -242,7 +242,7 @@
<select id="model-select" class="oh-select oh-select--sm ml-2 mb-2" style="width: 200px;">
<option value="payslip">Payslip</option>
<option value="allowance">Allowance & Deduction</option>
</select>
</select>
<!-- Pivot Container -->
<div id="pivot-container" class="mb-5" style="width: 100%; overflow-x: auto;">
@@ -260,11 +260,11 @@
// Hide all containers first
$(".pivot-wrapper").hide();
// Determine current container and row config
let containerId = "";
let rowsConfig = [];
if (model === "payslip") {
containerId = "pivot-payslip";
rowsConfig = ["Employee","Basic Salary","Gross Pay","Net Pay","Status"];
@@ -272,7 +272,7 @@
containerId = "pivot-allowance";
rowsConfig = ["Employee","Allowance & Deduction","Allowance & Deduction Title","Allowance & Deduction Amount"];
}
// Show relevant container
$("#" + containerId).show();
@@ -280,20 +280,20 @@
$.getJSON(url, function (data) {
// Add Plotly renderers correctly
let plotlyRenderers = $.pivotUtilities.plotly_renderers;
// Initialize pivot table with Plotly enabled
$("#" + containerId).pivotUI(data, {
rows: rowsConfig,
cols: [], // Default columns
aggregatorName: "Count", // Default aggregator
rendererName: "Table", // Default view as Table
renderers: $.extend(
$.pivotUtilities.renderers,
plotlyRenderers // Adding Plotly renderers
),
onRefresh: function (config) {
let currentRenderer = config.rendererName;
if (
@@ -307,10 +307,10 @@
} else {
$("#export-btn").hide(); // Hide button for charts
}
// ✅ Hide fields from the dropdown but keep them visible in the table
let hiddenFields = ["Allowance Amount", "Deduction Amount"];
setTimeout(function () {
$(".pvtAttrDropdown option").each(function () {
if (hiddenFields.includes($(this).text())) {
@@ -324,12 +324,12 @@
window.loadFilteredPivotData =function loadFilteredPivotData() {
const selectedModel = $("#model-select").val();
const formData = $("#filterForm").serialize();
$(".pivot-wrapper").hide();
let containerId = "";
let rowsConfig = [];
if (model === "payslip") {
containerId = "pivot-payslip";
rowsConfig = ["Employee","Basic Salary","Gross Pay","Net Pay","Status"];
@@ -337,13 +337,13 @@
containerId = "pivot-allowance";
rowsConfig = ["Employee","Allowance & Deduction","Allowance & Deduction Title","Allowance & Deduction Amount"];
}
$("#" + containerId).show();
$.getJSON(`payroll-pivot?model=${selectedModel}&${formData}`, function (data) {
const plotlyRenderers = $.pivotUtilities.plotly_renderers;
$("#" + containerId).pivotUI(data, {
rows: rowsConfig,
cols: [],
@@ -357,14 +357,14 @@
} else {
$("#export-btn").hide();
}
}
});
});
}
// Export to Excel on button click
$("#export-btn").on("click", function () {
let visiblePivot = $(".pivot-wrapper:visible .pvtTable").closest(".pivot-wrapper");
@@ -382,14 +382,14 @@
alert("No table found to export.");
return;
}
const workbook = new ExcelJS.Workbook();
const worksheet = workbook.addWorksheet("Pivot Data");
const baseRow = 5;
const baseCol = 5;
let currentRow = baseRow;
// Add company details first (if not 'all')
if ('{{company}}' !== 'all') {
const companyDetails = {
@@ -400,7 +400,7 @@
city: "{{ company.city|escapejs }}",
zip: "{{ company.zip|escapejs }}"
};
function getBase64FromUrl(url) {
return fetch(url)
.then(response => response.blob())
@@ -411,7 +411,7 @@
reader.readAsDataURL(blob);
}));
}
const logoUrl = "{{ protocol }}://{{ host }}{{ company.icon.url }}";
await getBase64FromUrl(logoUrl).then((base64) => {
const base64Data = base64.split(',')[1];
@@ -419,13 +419,13 @@
base64: base64Data,
extension: 'png'
});
worksheet.addImage(imageId, {
tl: { col: baseCol - 1, row: currentRow - 1 },
ext: { width: 80, height: 80 }
});
});
// Merge cells for company details text
const companyTextCell = worksheet.getCell(currentRow, baseCol + 1);
worksheet.mergeCells(currentRow, baseCol + 1, currentRow, baseCol + 2);
@@ -443,51 +443,51 @@
wrapText: true
};
worksheet.getRow(currentRow).height = 80;
currentRow += 2; // Leave a blank row
}
// Add timestamp
const timestamp = new Date().toLocaleDateString('en-GB') + ' ' +
new Date().toLocaleTimeString('en-US', {
hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: true
});
const downloadCell = worksheet.getCell(currentRow, baseCol);
worksheet.mergeCells(currentRow, baseCol, currentRow, baseCol + 3);
downloadCell.value = `Generated on: ${timestamp}`;
downloadCell.alignment = { horizontal: 'left', vertical: 'middle', wrapText: true };
downloadCell.font = { size: 10, italic: true, color: { argb: 'FF666666' }, bold: true };
currentRow += 3; // Leave some rows before the table
// ------------------------
// Render pivot table
// ------------------------
const cellMap = {};
const allRows = Array.from(table.rows);
const lastRowIndex = allRows.length - 1;
allRows.forEach((row, rowIndex) => {
let colIndex = baseCol;
Array.from(row.cells).forEach((cell) => {
while (cellMap[`${currentRow + rowIndex}-${colIndex}`]) {
colIndex++;
}
const rowspan = parseInt(cell.getAttribute("rowspan")) || 1;
const colspan = parseInt(cell.getAttribute("colspan")) || 1;
const cellValue = cell.textContent.trim();
const excelCell = worksheet.getCell(currentRow + rowIndex, colIndex);
excelCell.value = cellValue;
const isHeader = rowIndex === 0;
const isLastRow = rowIndex === lastRowIndex;
excelCell.font = {
bold: isHeader || isLastRow,
size: isHeader ? 12 : 11,
@@ -497,7 +497,7 @@
'FF000000'
}
};
excelCell.fill = {
type: 'pattern',
pattern: 'solid',
@@ -515,7 +515,7 @@
right: { style: 'thin' }
};
excelCell.alignment = { horizontal: "center", vertical: "middle" };
// Merge
if (rowspan > 1 || colspan > 1) {
worksheet.mergeCells(
@@ -524,7 +524,7 @@
currentRow + rowIndex + rowspan - 1,
colIndex + colspan - 1
);
for (let r = 0; r < rowspan; r++) {
for (let c = 0; c < colspan; c++) {
cellMap[`${currentRow + rowIndex + r}-${colIndex + c}`] = true;
@@ -533,15 +533,15 @@
} else {
cellMap[`${currentRow + rowIndex}-${colIndex}`] = true;
}
colIndex++;
});
});
worksheet.getRow(currentRow + lastRowIndex).height = 25; // adjust height for Total
worksheet.getRow(currentRow).height = 30; // adjust height for Heading
// Auto-adjust column widths
worksheet.columns.forEach(column => {
let maxLength = 2;
@@ -551,13 +551,13 @@
});
column.width = maxLength + 3;
});
// Save
const buffer = await workbook.xlsx.writeBuffer();
const blob = new Blob([buffer], {
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
});
const link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.download = filename;
@@ -574,8 +574,8 @@
loadPivotData(selectedModel); // Reload pivot data with selected model
});
});
</script>

View File

@@ -196,7 +196,7 @@
<option value="employeeobjective">Employee Objective</option>
<option value="feedback">Feedback</option>
</select>
<!-- Pivot Container -->
<div id="pivot-container" class="mb-5" style="width: 100%; overflow-x: auto;">
@@ -216,11 +216,11 @@
function loadPivotData(model) {
// Hide all containers first
$(".pivot-wrapper").hide();
// Determine current container and row config
let containerId = "";
let rowsConfig = [];
if (model === "feedback") {
containerId = "pivot-feedback";
rowsConfig = ["Title","Employee","Manager","Answerable Employees","Answered Employees","Questions","Answer"];
@@ -231,14 +231,14 @@
containerId = "pivot-employeeobjective";
rowsConfig = ["Employee", "Objective","Employee Keyresult","Keyresult Target Value","Keyresult Current Value"];
}
// Show relevant container
$("#" + containerId).show();
// Fetch and render data in its own container
$.getJSON(`pms-pivot?model=${model}`, function (data) {
let plotlyRenderers = $.pivotUtilities.plotly_renderers;
$("#" + containerId).pivotUI(data, {
rows: rowsConfig,
cols: [],
@@ -252,9 +252,9 @@
} else {
$("#export-btn").hide();
}
$(".pvtTotal, .pvtTotalLabel, .pvtGrandTotal, .pvtAggregator").hide();
setTimeout(() => {
$(".pvtAttrDropdown option").each(function () {
if (hiddenFields.includes($(this).text())) {
@@ -271,12 +271,12 @@
window.loadFilteredPivotData =function loadFilteredPivotData() {
const selectedModel = $("#model-select").val();
const formData = $("#filterForm").serialize();
$(".pivot-wrapper").hide();
let containerId = "";
let rowsConfig = [];
if (selectedModel === "feedback") {
containerId = "pivot-feedback";
rowsConfig = ["Title","Employee", "Manager", "Answerable Employees", "Answered Employees", "Questions", "Answer"];
@@ -287,15 +287,15 @@
containerId = "pivot-employeeobjective";
rowsConfig = ["Employee", "Objective", "Employee Keyresult", "Keyresult Target Value", "Keyresult Current Value"];
}
$("#" + containerId).show();
$.getJSON(`pms-pivot?model=${selectedModel}&${formData}`, function (data) {
console.log("Filtered data:", data);
const plotlyRenderers = $.pivotUtilities.plotly_renderers;
$("#" + containerId).pivotUI(data, {
rows: rowsConfig,
cols: [],
@@ -309,24 +309,24 @@
} else {
$("#export-btn").hide();
}
$(".pvtTotal, .pvtTotalLabel, .pvtGrandTotal, .pvtAggregator").hide();
}
});
});
}
// Listen to dropdown
$("#model-select").on("change", function () {
let selectedModel = $(this).val();
loadPivotData(selectedModel);
});
// Initial load
loadPivotData("objective");
// Export to Excel on button click
$("#export-btn").on("click", function () {
let visiblePivot = $(".pivot-wrapper:visible .pvtTable").closest(".pivot-wrapper");
@@ -343,14 +343,14 @@
alert("No table found to export.");
return;
}
const workbook = new ExcelJS.Workbook();
const worksheet = workbook.addWorksheet("Pivot Data");
const baseRow = 5;
const baseCol = 5;
let currentRow = baseRow;
// Add company details first (if not 'all')
if ('{{company}}' !== 'all') {
const companyDetails = {
@@ -361,7 +361,7 @@
city: "{{ company.city|escapejs }}",
zip: "{{ company.zip|escapejs }}"
};
function getBase64FromUrl(url) {
return fetch(url)
.then(response => response.blob())
@@ -372,7 +372,7 @@
reader.readAsDataURL(blob);
}));
}
const logoUrl = "{{ protocol }}://{{ host }}{{ company.icon.url }}";
await getBase64FromUrl(logoUrl).then((base64) => {
const base64Data = base64.split(',')[1];
@@ -380,13 +380,13 @@
base64: base64Data,
extension: 'png'
});
worksheet.addImage(imageId, {
tl: { col: baseCol - 1, row: currentRow - 1 },
ext: { width: 80, height: 80 }
});
});
// Merge cells for company details text
const companyTextCell = worksheet.getCell(currentRow, baseCol + 1);
worksheet.mergeCells(currentRow, baseCol + 1, currentRow, baseCol + 2);
@@ -404,24 +404,24 @@
wrapText: true
};
worksheet.getRow(currentRow).height = 80;
currentRow += 2; // Leave a blank row
}
// Add timestamp
const timestamp = new Date().toLocaleDateString('en-GB') + ' ' +
new Date().toLocaleTimeString('en-US', {
hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: true
});
const downloadCell = worksheet.getCell(currentRow, baseCol);
worksheet.mergeCells(currentRow, baseCol, currentRow, baseCol + 3);
downloadCell.value = `Generated on: ${timestamp}`;
downloadCell.alignment = { horizontal: 'left', vertical: 'middle', wrapText: true };
downloadCell.font = { size: 10, italic: true, color: { argb: 'FF666666' }, bold: true };
currentRow += 3; // Leave some rows before the table
// ------------------------
// Render pivot table
// ------------------------
@@ -431,9 +431,9 @@
row.classList.contains("pvtTotal") ||
row.classList.contains("pvtGrandTotal")
) return;
let colIndex = baseCol;
Array.from(row.cells).forEach((cell) => {
if (
cell.classList.contains("pvtTotal") ||
@@ -441,18 +441,18 @@
cell.classList.contains("pvtAggregator") ||
cell.classList.contains("pvtGrandTotal")
) return;
while (cellMap[`${currentRow + rowIndex}-${colIndex}`]) {
colIndex++;
}
const rowspan = parseInt(cell.getAttribute("rowspan")) || 1;
const colspan = parseInt(cell.getAttribute("colspan")) || 1;
const cellValue = cell.textContent.trim();
const excelCell = worksheet.getCell(currentRow + rowIndex, colIndex);
excelCell.value = cellValue;
excelCell.font = {
bold: rowIndex === 0,
size: rowIndex === 0 ? 12 : 11,
@@ -470,7 +470,7 @@
right: { style: 'thin' }
};
excelCell.alignment = { horizontal: "center", vertical: "middle" };
// Merge
if (rowspan > 1 || colspan > 1) {
worksheet.mergeCells(
@@ -479,7 +479,7 @@
currentRow + rowIndex + rowspan - 1,
colIndex + colspan - 1
);
for (let r = 0; r < rowspan; r++) {
for (let c = 0; c < colspan; c++) {
cellMap[`${currentRow + rowIndex + r}-${colIndex + c}`] = true;
@@ -488,14 +488,14 @@
} else {
cellMap[`${currentRow + rowIndex}-${colIndex}`] = true;
}
colIndex++;
});
});
// Header row height
worksheet.getRow(currentRow).height = 30;
// Auto-adjust column widths
worksheet.columns.forEach(column => {
let maxLength = 5;
@@ -505,21 +505,21 @@
});
column.width = maxLength + 0;
});
// Save
const buffer = await workbook.xlsx.writeBuffer();
const blob = new Blob([buffer], {
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
});
const link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.download = filename;
link.click();
}
});
</script>

View File

@@ -60,7 +60,7 @@
<label class="oh-label">{% trans 'Job Position' %}</label>
{{ f.form.job_position_id }}
</div>
<div class="oh-input-group">
<label class="oh-label">{% trans 'Is Hired' %}?</label>
{{ f.form.hired }}
@@ -77,12 +77,12 @@
<label class="oh-label">{% trans 'Email' %}</label>
{{ f.form.email }}
</div>
<div class="oh-input-group">
<label class="oh-label">{% trans 'Gender' %}</label>
{{ f.form.gender }}
</div>
<div class="oh-input-group">
<label class="oh-label">{% trans 'State' %}</label>
<select name="state" class="oh-select-2 w-100 country" id="state">
@@ -98,7 +98,7 @@
<label class="oh-label">{% trans 'Stage Type' %}</label>
{{ f.form.stage_id__stage_type }}
</div>
<div class="oh-input-group">
<label class="oh-label">{% trans 'Is Canceled' %}?</label>
{{ f.form.canceled }}
@@ -172,7 +172,7 @@
</div>
</div>
</div>
<div class="oh-accordion">
<div class="oh-accordion-header">{% trans "Onboarding" %}</div>
<div class="oh-accordion-body">
@@ -195,7 +195,7 @@
{{ fo.form.recruitment_id__company_id }}
</div>
</div>
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<label class="oh-label">{% trans 'Candidates' %}</label>
@@ -246,7 +246,7 @@
<option value="recruitment">{% trans "Recruitment" %}</option>
<option value="onboarding">{% trans "Onboarding" %}</option>
</select>
<!-- Pivot Container -->
<div id="pivot-container" class="mb-5" style="width: 100%; overflow-x: auto;">
@@ -265,7 +265,7 @@
// Hide all containers first
$(".pivot-wrapper").hide();
// Determine current container and row config
let containerId = "";
let rowsConfig = [];
@@ -280,14 +280,14 @@
containerId = "pivot-onboarding";
rowsConfig = ["Recruitment","Candidates","Stage","Stage Manager","Task","Task Manager","Company"];
}
// Show relevant container
$("#" + containerId).show();
$.getJSON(url, function (data) {
// Add Plotly renderers correctly
let plotlyRenderers = $.pivotUtilities.plotly_renderers;
// Initialize pivot table with Plotly enabled
$("#" + containerId).pivotUI(data, {
rows: rowsConfig,
@@ -296,7 +296,7 @@
rendererName: "Table", // Default view as Table
onRefresh: function (config) {
let currentRenderer = config.rendererName;
if (currentRenderer === "Table" || currentRenderer === "Table Barchart" ||
if (currentRenderer === "Table" || currentRenderer === "Table Barchart" ||
currentRenderer === "Heatmap" || currentRenderer === "Row Heatmap" || currentRenderer === "Col Heatmap" ) {
$("#export-btn").show(); // Show button for tables
} else {
@@ -329,12 +329,12 @@
window.loadFilteredPivotData =function loadFilteredPivotData() {
const selectedModel = $("#model-select").val();
const formData = $("#filterForm").serialize();
$(".pivot-wrapper").hide();
let containerId = "";
let rowsConfig = [];
if (selectedModel === "candidate") {
containerId = "pivot-candidate";
rowsConfig = ["Recruitment","Job Position","Department","Candidate","Gender","Email"];
@@ -345,13 +345,13 @@
containerId = "pivot-onboarding";
rowsConfig = ["Recruitment","Candidates","Stage","Stage Manager","Task","Task Manager","Company"];
}
$("#" + containerId).show();
$.getJSON(`recruitment-pivot?model=${selectedModel}&${formData}`, function (data) {
const plotlyRenderers = $.pivotUtilities.plotly_renderers;
$("#" + containerId).pivotUI(data, {
rows: rowsConfig,
cols: [],
@@ -365,7 +365,7 @@
} else {
$("#export-btn").hide();
}
}
});
});
@@ -374,7 +374,7 @@
// Initial load with all models
loadPivotData("candidate");
// Model selection change event
$("#model-select").on("change", function () {
let selectedModel = $(this).val();
@@ -397,14 +397,14 @@
alert("No table found to export.");
return;
}
const workbook = new ExcelJS.Workbook();
const worksheet = workbook.addWorksheet("Pivot Data");
const baseRow = 5;
const baseCol = 5;
let currentRow = baseRow;
// Add company details first (if not 'all')
if ('{{company}}' !== 'all') {
const companyDetails = {
@@ -415,7 +415,7 @@
city: "{{ company.city|escapejs }}",
zip: "{{ company.zip|escapejs }}"
};
function getBase64FromUrl(url) {
return fetch(url)
.then(response => response.blob())
@@ -426,7 +426,7 @@
reader.readAsDataURL(blob);
}));
}
const logoUrl = "{{ protocol }}://{{ host }}{{ company.icon.url }}";
await getBase64FromUrl(logoUrl).then((base64) => {
const base64Data = base64.split(',')[1];
@@ -434,13 +434,13 @@
base64: base64Data,
extension: 'png'
});
worksheet.addImage(imageId, {
tl: { col: baseCol - 1, row: currentRow - 1 },
ext: { width: 80, height: 80 }
});
});
// Merge cells for company details text
const companyTextCell = worksheet.getCell(currentRow, baseCol + 1);
worksheet.mergeCells(currentRow, baseCol + 1, currentRow, baseCol + 2);
@@ -458,35 +458,35 @@
wrapText: true
};
worksheet.getRow(currentRow).height = 80;
currentRow += 2; // Leave a blank row
}
// Add timestamp
const timestamp = new Date().toLocaleDateString('en-GB') + ' ' +
new Date().toLocaleTimeString('en-US', {
hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: true
});
const downloadCell = worksheet.getCell(currentRow, baseCol);
worksheet.mergeCells(currentRow, baseCol, currentRow, baseCol + 3);
downloadCell.value = `Generated on: ${timestamp}`;
downloadCell.alignment = { horizontal: 'left', vertical: 'middle', wrapText: true };
downloadCell.font = { size: 10, italic: true, color: { argb: 'FF666666' }, bold: true };
currentRow += 3; // Leave some rows before the table
// ------------------------
// Render pivot table
// ------------------------
const cellMap = {};
const allRows = Array.from(table.rows);
const lastRowIndex = allRows.length - 1;
allRows.forEach((row, rowIndex) => {
let colIndex = baseCol;
Array.from(row.cells).forEach((cell) => {
if (
@@ -495,21 +495,21 @@
cell.classList.contains("pvtAggregator") ||
cell.classList.contains("pvtGrandTotal")
) return;
while (cellMap[`${currentRow + rowIndex}-${colIndex}`]) {
colIndex++;
}
const rowspan = parseInt(cell.getAttribute("rowspan")) || 1;
const colspan = parseInt(cell.getAttribute("colspan")) || 1;
const cellValue = cell.textContent.trim();
const excelCell = worksheet.getCell(currentRow + rowIndex, colIndex);
excelCell.value = cellValue;
const isHeader = rowIndex === 0;
const isLastRow = rowIndex === lastRowIndex;
excelCell.font = {
bold: isHeader || isLastRow,
size: isHeader ? 12 : 11,
@@ -519,7 +519,7 @@
'FF000000'
}
};
excelCell.fill = {
type: 'pattern',
pattern: 'solid',
@@ -537,7 +537,7 @@
right: { style: 'thin' }
};
excelCell.alignment = { horizontal: "center", vertical: "middle" };
// Merge
if (rowspan > 1 || colspan > 1) {
worksheet.mergeCells(
@@ -546,7 +546,7 @@
currentRow + rowIndex + rowspan - 1,
colIndex + colspan - 1
);
for (let r = 0; r < rowspan; r++) {
for (let c = 0; c < colspan; c++) {
cellMap[`${currentRow + rowIndex + r}-${colIndex + c}`] = true;
@@ -555,15 +555,15 @@
} else {
cellMap[`${currentRow + rowIndex}-${colIndex}`] = true;
}
colIndex++;
});
});
worksheet.getRow(currentRow + lastRowIndex).height = 25; // adjust height for Total
worksheet.getRow(currentRow).height = 30; // adjust height for Heading
// Auto-adjust column widths
worksheet.columns.forEach(column => {
let maxLength = 2;
@@ -573,13 +573,13 @@
});
column.width = maxLength + 3;
});
// Save
const buffer = await workbook.xlsx.writeBuffer();
const blob = new Blob([buffer], {
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
});
const link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.download = filename;
@@ -587,7 +587,7 @@
}
});
</script>

View File

@@ -1,70 +1,84 @@
from django.urls import path
from report.views import asset_report, employee_report,attendance_report,leave_report,payroll_report, pms_report,recruitment_report
from django.apps import apps
from django.urls import path
from report.views import (
asset_report,
attendance_report,
employee_report,
leave_report,
payroll_report,
pms_report,
recruitment_report,
)
urlpatterns = [
path("employee-report",employee_report.employee_report,name='employee-report'),
path("employee-pivot",employee_report.employee_pivot,name='employee-pivot'),
path("employee-report", employee_report.employee_report, name="employee-report"),
path("employee-pivot", employee_report.employee_pivot, name="employee-pivot"),
]
if apps.is_installed("recruitment"):
urlpatterns.extend(
[
path("recruitment-report",recruitment_report.recruitment_report,name='recruitment-report'),
path("recruitment-pivot",recruitment_report.recruitment_pivot,name='recruitment-pivot'),
path(
"recruitment-report",
recruitment_report.recruitment_report,
name="recruitment-report",
),
path(
"recruitment-pivot",
recruitment_report.recruitment_pivot,
name="recruitment-pivot",
),
]
)
if apps.is_installed("attendance"):
urlpatterns.extend(
[
path("attendance-report",attendance_report.attendance_report,name='attendance-report'),
path("attendance-pivot",attendance_report.attendance_pivot,name='attendance-pivot'),
path(
"attendance-report",
attendance_report.attendance_report,
name="attendance-report",
),
path(
"attendance-pivot",
attendance_report.attendance_pivot,
name="attendance-pivot",
),
]
)
if apps.is_installed("leave"):
urlpatterns.extend(
[
path("leave-report",leave_report.leave_report, name="leave-report"),
path("leave-pivot",leave_report.leave_pivot,name='leave-pivot'),
path("leave-report", leave_report.leave_report, name="leave-report"),
path("leave-pivot", leave_report.leave_pivot, name="leave-pivot"),
]
)
if apps.is_installed("payroll"):
urlpatterns.extend(
[
path("payroll-report",payroll_report.payroll_report, name="payroll-report"),
path("payroll-pivot",payroll_report.payroll_pivot,name='payroll-pivot'),
path(
"payroll-report", payroll_report.payroll_report, name="payroll-report"
),
path("payroll-pivot", payroll_report.payroll_pivot, name="payroll-pivot"),
]
)
if apps.is_installed("asset"):
urlpatterns.extend(
[
path("asset-report",asset_report.asset_report, name="asset-report"),
path("asset-pivot",asset_report.asset_pivot,name='asset-pivot'),
path("asset-report", asset_report.asset_report, name="asset-report"),
path("asset-pivot", asset_report.asset_pivot, name="asset-pivot"),
]
)
if apps.is_installed("pms"):
urlpatterns.extend(
[
path("pms-report",pms_report.pms_report, name="pms-report"),
path("pms-pivot",pms_report.pms_pivot,name='pms-pivot'),
path("pms-report", pms_report.pms_report, name="pms-report"),
path("pms-pivot", pms_report.pms_pivot, name="pms-pivot"),
]
)

View File

@@ -1,25 +1,32 @@
from django.apps import apps
from django.http import JsonResponse
from django.shortcuts import render
from django.apps import apps
if apps.is_installed("asset"):
from asset.filters import AssetFilter
from asset.models import Asset
from base.models import Company
from horilla_views.cbv_methods import login_required, permission_required
from asset.models import Asset
@login_required
@permission_required(perm="asset.view_asset")
def asset_report(request):
company = 'all'
company = "all"
selected_company = request.session.get("selected_company")
if selected_company != 'all':
if selected_company != "all":
company = Company.objects.filter(id=selected_company).first()
asset_filter_form = AssetFilter()
return render(request, "report/asset_report.html",{"company":company,"asset_filter_form": asset_filter_form.form,})
return render(
request,
"report/asset_report.html",
{
"company": company,
"asset_filter_form": asset_filter_form.form,
},
)
@login_required
@permission_required(perm="asset.view_asset")
@@ -27,52 +34,121 @@ if apps.is_installed("asset"):
qs = Asset.objects.all()
if asset_name := request.GET.get("asset_name"):
qs = qs.filter(asset_name = asset_name)
qs = qs.filter(asset_name=asset_name)
if asset_tracking_id := request.GET.get("asset_tracking_id"):
qs = qs.filter(asset_tracking_id = asset_tracking_id)
qs = qs.filter(asset_tracking_id=asset_tracking_id)
if asset_purchase_cost := request.GET.get("asset_purchase_cost"):
qs = qs.filter(asset_purchase_cost = asset_purchase_cost)
qs = qs.filter(asset_purchase_cost=asset_purchase_cost)
if asset_lot_number_id := request.GET.get("asset_lot_number_id"):
qs = qs.filter(asset_lot_number_id = asset_lot_number_id)
qs = qs.filter(asset_lot_number_id=asset_lot_number_id)
if asset_category_id := request.GET.get("asset_category_id"):
qs = qs.filter(asset_category_id = asset_category_id)
qs = qs.filter(asset_category_id=asset_category_id)
if asset_status := request.GET.get("asset_status"):
qs = qs.filter(asset_status = asset_status)
qs = qs.filter(asset_status=asset_status)
if asset_purchase_date := request.GET.get("asset_purchase_date"):
qs = qs.filter(asset_purchase_date = asset_purchase_date)
qs = qs.filter(asset_purchase_date=asset_purchase_date)
data = list(qs.values(
"asset_name","asset_purchase_date","asset_tracking_id",
"asset_purchase_cost","asset_status","asset_category_id__asset_category_name","asset_lot_number_id__lot_number",
"expiry_date","assetassignment__assigned_by_employee_id__employee_work_info__department_id__department",
"assetassignment__assigned_by_employee_id__employee_work_info__job_position_id__job_position",
"assetassignment__assigned_by_employee_id__employee_work_info__job_role_id__job_role",
"assetassignment__assigned_by_employee_id__email","assetassignment__assigned_by_employee_id__phone",
"assetassignment__assigned_by_employee_id__gender","assetassignment__assigned_by_employee_id__employee_first_name",
"assetassignment__assigned_by_employee_id__employee_last_name","assetassignment__assigned_date",
"assetassignment__return_date","assetassignment__return_status",
))
data = list(
qs.values(
"asset_name",
"asset_purchase_date",
"asset_tracking_id",
"asset_purchase_cost",
"asset_status",
"asset_category_id__asset_category_name",
"asset_lot_number_id__lot_number",
"expiry_date",
"assetassignment__assigned_by_employee_id__employee_work_info__department_id__department",
"assetassignment__assigned_by_employee_id__employee_work_info__job_position_id__job_position",
"assetassignment__assigned_by_employee_id__employee_work_info__job_role_id__job_role",
"assetassignment__assigned_by_employee_id__email",
"assetassignment__assigned_by_employee_id__phone",
"assetassignment__assigned_by_employee_id__gender",
"assetassignment__assigned_by_employee_id__employee_first_name",
"assetassignment__assigned_by_employee_id__employee_last_name",
"assetassignment__assigned_date",
"assetassignment__return_date",
"assetassignment__return_status",
)
)
data_list = [
{
"Asset Name" : item["asset_name"],
"Asset User": f"{item['assetassignment__assigned_by_employee_id__employee_first_name']} {item['assetassignment__assigned_by_employee_id__employee_last_name']}" if item["assetassignment__assigned_by_employee_id__employee_first_name"] or item["assetassignment__assigned_by_employee_id__employee_last_name"] else "-",
"Email":item["assetassignment__assigned_by_employee_id__email"] if item["assetassignment__assigned_by_employee_id__email"] else "-",
"Phone":item["assetassignment__assigned_by_employee_id__phone"] if item["assetassignment__assigned_by_employee_id__phone"] else "-",
"Gender":item["assetassignment__assigned_by_employee_id__gender"] if item["assetassignment__assigned_by_employee_id__gender"] else "-",
"Department":item["assetassignment__assigned_by_employee_id__employee_work_info__department_id__department"] if item["assetassignment__assigned_by_employee_id__employee_work_info__department_id__department"] else "-",
"Job Position":item["assetassignment__assigned_by_employee_id__employee_work_info__job_position_id__job_position"] if item["assetassignment__assigned_by_employee_id__employee_work_info__job_position_id__job_position"] else "-",
"Job Role":item["assetassignment__assigned_by_employee_id__employee_work_info__job_role_id__job_role"] if item["assetassignment__assigned_by_employee_id__employee_work_info__job_role_id__job_role"] else "-",
"Asset Purchce Date":item["asset_purchase_date"],
"Asset Cost":item["asset_purchase_cost"],
"Status":item["asset_status"],
"Assigned Date":item["assetassignment__assigned_date"] if item["assetassignment__assigned_date"] else "-",
"Return Date":item["assetassignment__return_date"] if item["assetassignment__return_date"] else "-",
"Return Condition":item["assetassignment__return_status"] if item["assetassignment__return_status"] else "-",
"Category":item["asset_category_id__asset_category_name"],
"Batch Number":item["asset_lot_number_id__lot_number"],
"Tracking ID":item["asset_tracking_id"],
"Expiry Date":item["expiry_date"] if item["expiry_date"] else "-",
}for item in data
"Asset Name": item["asset_name"],
"Asset User": (
f"{item['assetassignment__assigned_by_employee_id__employee_first_name']} {item['assetassignment__assigned_by_employee_id__employee_last_name']}"
if item[
"assetassignment__assigned_by_employee_id__employee_first_name"
]
or item[
"assetassignment__assigned_by_employee_id__employee_last_name"
]
else "-"
),
"Email": (
item["assetassignment__assigned_by_employee_id__email"]
if item["assetassignment__assigned_by_employee_id__email"]
else "-"
),
"Phone": (
item["assetassignment__assigned_by_employee_id__phone"]
if item["assetassignment__assigned_by_employee_id__phone"]
else "-"
),
"Gender": (
item["assetassignment__assigned_by_employee_id__gender"]
if item["assetassignment__assigned_by_employee_id__gender"]
else "-"
),
"Department": (
item[
"assetassignment__assigned_by_employee_id__employee_work_info__department_id__department"
]
if item[
"assetassignment__assigned_by_employee_id__employee_work_info__department_id__department"
]
else "-"
),
"Job Position": (
item[
"assetassignment__assigned_by_employee_id__employee_work_info__job_position_id__job_position"
]
if item[
"assetassignment__assigned_by_employee_id__employee_work_info__job_position_id__job_position"
]
else "-"
),
"Job Role": (
item[
"assetassignment__assigned_by_employee_id__employee_work_info__job_role_id__job_role"
]
if item[
"assetassignment__assigned_by_employee_id__employee_work_info__job_role_id__job_role"
]
else "-"
),
"Asset Purchce Date": item["asset_purchase_date"],
"Asset Cost": item["asset_purchase_cost"],
"Status": item["asset_status"],
"Assigned Date": (
item["assetassignment__assigned_date"]
if item["assetassignment__assigned_date"]
else "-"
),
"Return Date": (
item["assetassignment__return_date"]
if item["assetassignment__return_date"]
else "-"
),
"Return Condition": (
item["assetassignment__return_status"]
if item["assetassignment__return_status"]
else "-"
),
"Category": item["asset_category_id__asset_category_name"],
"Batch Number": item["asset_lot_number_id__lot_number"],
"Tracking ID": item["asset_tracking_id"],
"Expiry Date": item["expiry_date"] if item["expiry_date"] else "-",
}
for item in data
]
return JsonResponse(data_list, safe=False)

View File

@@ -1,16 +1,15 @@
from datetime import time,datetime
from django.http import JsonResponse
from django.shortcuts import render
from datetime import datetime, time
from django.apps import apps
from django.http import JsonResponse
from django.shortcuts import render
if apps.is_installed("attendance"):
from attendance.filters import AttendanceFilters
from attendance.models import Attendance
from base.models import Company
from horilla_views.cbv_methods import login_required, permission_required
from attendance.models import Attendance
def convert_time_to_decimal_w(time_str):
try:
@@ -20,15 +19,13 @@ if apps.is_installed("attendance"):
hours, minutes = time_str.hour, time_str.minute
else:
return "00.00"
# Format as HH.MM
formatted_time = f"{hours:02}.{minutes:02}"
return formatted_time
except (ValueError, TypeError):
return "00.00"
def convert_time_to_decimal(time_str):
"""Format time as HH.MM for aggregation."""
try:
@@ -45,30 +42,53 @@ if apps.is_installed("attendance"):
except Exception:
return "00.00"
@login_required
@login_required
@permission_required(perm="attendance.view_attendance")
def attendance_report(request):
company = 'all'
company = "all"
selected_company = request.session.get("selected_company")
if selected_company != 'all':
if selected_company != "all":
company = Company.objects.filter(id=selected_company).first()
return render(request, "report/attendance_report.html",{'company':company,"f": AttendanceFilters() })
return render(
request,
"report/attendance_report.html",
{"company": company, "f": AttendanceFilters()},
)
@login_required
@permission_required(perm="attendance.view_attendance")
def attendance_pivot(request):
qs =Attendance.objects.all()
qs = Attendance.objects.all()
filter_obj = AttendanceFilters(request.GET, queryset=qs)
qs = filter_obj.qs
data = list(qs.values(
'employee_id__employee_first_name','employee_id__employee_last_name','attendance_date','attendance_clock_in','attendance_clock_out',
'attendance_worked_hour','minimum_hour','attendance_overtime','at_work_second','work_type_id__work_type','shift_id__employee_shift',
'attendance_day__day','employee_id__gender','employee_id__email','employee_id__phone','employee_id__employee_work_info__department_id__department', 'employee_id__employee_work_info__job_role_id__job_role',
'employee_id__employee_work_info__job_position_id__job_position', 'employee_id__employee_work_info__employee_type_id__employee_type',
'employee_id__employee_work_info__experience', 'batch_attendance_id__title','employee_id__employee_work_info__company_id__company',
))
data = list(
qs.values(
"employee_id__employee_first_name",
"employee_id__employee_last_name",
"attendance_date",
"attendance_clock_in",
"attendance_clock_out",
"attendance_worked_hour",
"minimum_hour",
"attendance_overtime",
"at_work_second",
"work_type_id__work_type",
"shift_id__employee_shift",
"attendance_day__day",
"employee_id__gender",
"employee_id__email",
"employee_id__phone",
"employee_id__employee_work_info__department_id__department",
"employee_id__employee_work_info__job_role_id__job_role",
"employee_id__employee_work_info__job_position_id__job_position",
"employee_id__employee_work_info__employee_type_id__employee_type",
"employee_id__employee_work_info__experience",
"batch_attendance_id__title",
"employee_id__employee_work_info__company_id__company",
)
)
DAY = {
"monday": "Monday",
"tuesday": "Tuesday",
@@ -89,44 +109,80 @@ if apps.is_installed("attendance"):
"Gender": choice_gender.get(item["employee_id__gender"]),
"Email": item["employee_id__email"],
"Phone": item["employee_id__phone"],
"Department": item["employee_id__employee_work_info__department_id__department"] if item["employee_id__employee_work_info__department_id__department"] else "-",
"Job Position": item["employee_id__employee_work_info__job_position_id__job_position"] if item["employee_id__employee_work_info__job_position_id__job_position"] else "-",
"Job Role": item["employee_id__employee_work_info__job_role_id__job_role"] if item["employee_id__employee_work_info__job_role_id__job_role"] else "-",
"Work Type": item["work_type_id__work_type"] if item["work_type_id__work_type"] else "-",
"Shift": item["shift_id__employee_shift"] if item["shift_id__employee_shift"] else "-",
"Department": (
item["employee_id__employee_work_info__department_id__department"]
if item[
"employee_id__employee_work_info__department_id__department"
]
else "-"
),
"Job Position": (
item[
"employee_id__employee_work_info__job_position_id__job_position"
]
if item[
"employee_id__employee_work_info__job_position_id__job_position"
]
else "-"
),
"Job Role": (
item["employee_id__employee_work_info__job_role_id__job_role"]
if item["employee_id__employee_work_info__job_role_id__job_role"]
else "-"
),
"Work Type": (
item["work_type_id__work_type"]
if item["work_type_id__work_type"]
else "-"
),
"Shift": (
item["shift_id__employee_shift"]
if item["shift_id__employee_shift"]
else "-"
),
"Experience": item["employee_id__employee_work_info__experience"],
"Attendance Date": item['attendance_date'],
"Attendance Day": DAY.get(item['attendance_day__day']),
"Clock-in": format_time(item['attendance_clock_in']),
"Clock-out": format_time(item['attendance_clock_out']),
"At Work": format_seconds_to_time(item['at_work_second']),
"Worked Hour": item['attendance_worked_hour'],
"Minimum Hour": item['minimum_hour'],
"Overtime": item['attendance_overtime'],
"Batch":item['batch_attendance_id__title'] if item['batch_attendance_id__title'] else "-",
"Company":item['employee_id__employee_work_info__company_id__company'],
"Attendance Date": item["attendance_date"],
"Attendance Day": DAY.get(item["attendance_day__day"]),
"Clock-in": format_time(item["attendance_clock_in"]),
"Clock-out": format_time(item["attendance_clock_out"]),
"At Work": format_seconds_to_time(item["at_work_second"]),
"Worked Hour": item["attendance_worked_hour"],
"Minimum Hour": item["minimum_hour"],
"Overtime": item["attendance_overtime"],
"Batch": (
item["batch_attendance_id__title"]
if item["batch_attendance_id__title"]
else "-"
),
"Company": item["employee_id__employee_work_info__company_id__company"],
# For correct total
"Clock-in Decimal": convert_time_to_decimal(item["attendance_clock_in"]),
"Clock-out Decimal": convert_time_to_decimal(item["attendance_clock_out"]),
"At Work Decimal": convert_time_to_decimal_w(format_seconds_to_time(item['at_work_second'])),
"Worked Hour Decimal": convert_time_to_decimal_w(item["attendance_worked_hour"]),
"Minimum Hour Decimal": convert_time_to_decimal_w(item["minimum_hour"]),
"Overtime Decimal": convert_time_to_decimal_w(item['attendance_overtime']),
"Clock-in Decimal": convert_time_to_decimal(
item["attendance_clock_in"]
),
"Clock-out Decimal": convert_time_to_decimal(
item["attendance_clock_out"]
),
"At Work Decimal": convert_time_to_decimal_w(
format_seconds_to_time(item["at_work_second"])
),
"Worked Hour Decimal": convert_time_to_decimal_w(
item["attendance_worked_hour"]
),
"Minimum Hour Decimal": convert_time_to_decimal_w(item["minimum_hour"]),
"Overtime Decimal": convert_time_to_decimal_w(
item["attendance_overtime"]
),
}
for item in data
]
return JsonResponse(data_list, safe=False)
# Helper function to format time
def format_time(time_value):
if isinstance(time_value, str): # In case time is string
time_value = datetime.strptime(time_value, "%H:%M:%S").time()
return time_value.strftime("%H:%M") if time_value else ""
def format_seconds_to_time(seconds):
"""Convert seconds to HH:MM format."""
try:
@@ -136,4 +192,3 @@ if apps.is_installed("attendance"):
return f"{hours:02}:{minutes:02}"
except (ValueError, TypeError):
return "00:00"

View File

@@ -3,54 +3,105 @@ from django.shortcuts import render
from base.models import Company
from employee.filters import EmployeeFilter
from horilla_views.cbv_methods import login_required, permission_required
from employee.models import Employee
from horilla_views.cbv_methods import login_required, permission_required
@login_required
@permission_required(perm="employee.view_employee")
def employee_report(request):
company = 'all'
company = "all"
selected_company = request.session.get("selected_company")
if selected_company != 'all':
if selected_company != "all":
company = Company.objects.filter(id=selected_company).first()
return render(request, "report/employee_report.html",{'company':company, "f":EmployeeFilter()})
return render(
request,
"report/employee_report.html",
{"company": company, "f": EmployeeFilter()},
)
@login_required
@permission_required(perm="employee.view_employee")
def employee_pivot(request):
qs = Employee.objects.all()
filtered_qs = EmployeeFilter(request.GET,queryset=qs)
filtered_qs = EmployeeFilter(request.GET, queryset=qs)
qs = filtered_qs.qs
data = list(qs.values(
'employee_first_name','employee_last_name', 'gender','email','phone','employee_work_info__department_id__department','employee_work_info__job_position_id__job_position',
'employee_work_info__job_role_id__job_role','employee_work_info__work_type_id__work_type','employee_work_info__shift_id__employee_shift','employee_work_info__employee_type_id__employee_type',
'employee_work_info__reporting_manager_id__employee_first_name','employee_work_info__reporting_manager_id__employee_last_name','employee_work_info__company_id__company','employee_work_info__date_joining',
'employee_work_info__experience'
))
data = list(
qs.values(
"employee_first_name",
"employee_last_name",
"gender",
"email",
"phone",
"employee_work_info__department_id__department",
"employee_work_info__job_position_id__job_position",
"employee_work_info__job_role_id__job_role",
"employee_work_info__work_type_id__work_type",
"employee_work_info__shift_id__employee_shift",
"employee_work_info__employee_type_id__employee_type",
"employee_work_info__reporting_manager_id__employee_first_name",
"employee_work_info__reporting_manager_id__employee_last_name",
"employee_work_info__company_id__company",
"employee_work_info__date_joining",
"employee_work_info__experience",
)
)
choice_gender = {
"male": "Male",
"female": "Female",
"other": "Other",
}
# Transform data to match format
data_list = [
{
"Name": f"{item['employee_first_name']} {item['employee_last_name']}",
"Name": f"{item['employee_first_name']} {item['employee_last_name']}",
"Gender": choice_gender.get(item["gender"]),
"Email": item["email"],
"Phone": item["phone"],
"Department": item["employee_work_info__department_id__department"] if item["employee_work_info__department_id__department"] else "-",
"Job Position": item["employee_work_info__job_position_id__job_position"] if item["employee_work_info__job_position_id__job_position"] else "-",
"Job Role": item["employee_work_info__job_role_id__job_role"] if item["employee_work_info__job_role_id__job_role"] else "-",
"Work Type": item["employee_work_info__work_type_id__work_type"] if item["employee_work_info__work_type_id__work_type"] else "-",
"Shift": item["employee_work_info__shift_id__employee_shift"] if item["employee_work_info__shift_id__employee_shift"] else "-",
"Employee Type": item["employee_work_info__employee_type_id__employee_type"] if item["employee_work_info__employee_type_id__employee_type"] else "-",
"Reporting Manager": f"{item['employee_work_info__reporting_manager_id__employee_first_name']} {item['employee_work_info__reporting_manager_id__employee_last_name']}" if item['employee_work_info__reporting_manager_id__employee_first_name'] else '-' ,
"Date of Joining": item["employee_work_info__date_joining"] if item["employee_work_info__date_joining"] else '-',
"Department": (
item["employee_work_info__department_id__department"]
if item["employee_work_info__department_id__department"]
else "-"
),
"Job Position": (
item["employee_work_info__job_position_id__job_position"]
if item["employee_work_info__job_position_id__job_position"]
else "-"
),
"Job Role": (
item["employee_work_info__job_role_id__job_role"]
if item["employee_work_info__job_role_id__job_role"]
else "-"
),
"Work Type": (
item["employee_work_info__work_type_id__work_type"]
if item["employee_work_info__work_type_id__work_type"]
else "-"
),
"Shift": (
item["employee_work_info__shift_id__employee_shift"]
if item["employee_work_info__shift_id__employee_shift"]
else "-"
),
"Employee Type": (
item["employee_work_info__employee_type_id__employee_type"]
if item["employee_work_info__employee_type_id__employee_type"]
else "-"
),
"Reporting Manager": (
f"{item['employee_work_info__reporting_manager_id__employee_first_name']} {item['employee_work_info__reporting_manager_id__employee_last_name']}"
if item["employee_work_info__reporting_manager_id__employee_first_name"]
else "-"
),
"Date of Joining": (
item["employee_work_info__date_joining"]
if item["employee_work_info__date_joining"]
else "-"
),
"Experience": round(float(item["employee_work_info__experience"] or 0), 2),
"Company": item["employee_work_info__company_id__company"],
}

View File

@@ -1,6 +1,6 @@
from django.apps import apps
from django.http import JsonResponse
from django.shortcuts import render
from django.apps import apps
if apps.is_installed("leave"):
@@ -9,40 +9,63 @@ if apps.is_installed("leave"):
from leave.filters import AssignedLeaveFilter, LeaveRequestFilter
from leave.models import AvailableLeave, LeaveRequest
@login_required
@permission_required(perm="leave.view_leaverequest")
def leave_report(request):
company = "all"
selected_company = request.session.get("selected_company")
if selected_company != 'all':
company = Company.objects.filter(id = selected_company).first()
if selected_company != "all":
company = Company.objects.filter(id=selected_company).first()
leave_request_filter = LeaveRequestFilter()
return render(request, "report/leave_report.html",{'company' : company, "form": leave_request_filter.form, "f": AssignedLeaveFilter(),} )
return render(
request,
"report/leave_report.html",
{
"company": company,
"form": leave_request_filter.form,
"f": AssignedLeaveFilter(),
},
)
@login_required
@permission_required(perm="leave.view_leaverequest")
def leave_pivot(request):
model_type = request.GET.get("model", "leave_request") # Default to LeaveRequest
model_type = request.GET.get(
"model", "leave_request"
) # Default to LeaveRequest
if model_type == "leave_request":
qs = LeaveRequest.objects.all()
leave_filter = LeaveRequestFilter(request.GET, queryset=qs)
qs = leave_filter.qs
data = list(qs.values(
"employee_id__employee_first_name","employee_id__employee_last_name","leave_type_id__name",
"start_date","start_date_breakdown","end_date","end_date_breakdown","requested_days","status",
'employee_id__gender','employee_id__email','employee_id__phone','employee_id__employee_work_info__department_id__department',
'employee_id__employee_work_info__job_role_id__job_role','employee_id__employee_work_info__job_position_id__job_position',
'employee_id__employee_work_info__employee_type_id__employee_type','employee_id__employee_work_info__experience',
'employee_id__employee_work_info__work_type_id__work_type','employee_id__employee_work_info__shift_id__employee_shift',
'employee_id__employee_work_info__company_id__company'
))
data = list(
qs.values(
"employee_id__employee_first_name",
"employee_id__employee_last_name",
"leave_type_id__name",
"start_date",
"start_date_breakdown",
"end_date",
"end_date_breakdown",
"requested_days",
"status",
"employee_id__gender",
"employee_id__email",
"employee_id__phone",
"employee_id__employee_work_info__department_id__department",
"employee_id__employee_work_info__job_role_id__job_role",
"employee_id__employee_work_info__job_position_id__job_position",
"employee_id__employee_work_info__employee_type_id__employee_type",
"employee_id__employee_work_info__experience",
"employee_id__employee_work_info__work_type_id__work_type",
"employee_id__employee_work_info__shift_id__employee_shift",
"employee_id__employee_work_info__company_id__company",
)
)
BREAKDOWN_MAP = {
"full_day": "Full Day",
"first_half": "First Half",
@@ -67,38 +90,95 @@ if apps.is_installed("leave"):
"Gender": choice_gender.get(item["employee_id__gender"]),
"Email": item["employee_id__email"],
"Phone": item["employee_id__phone"],
"Department": item["employee_id__employee_work_info__department_id__department"] if item["employee_id__employee_work_info__department_id__department"] else "-",
"Job Position": item["employee_id__employee_work_info__job_position_id__job_position"] if item["employee_id__employee_work_info__job_position_id__job_position"] else "-",
"Job Role": item["employee_id__employee_work_info__job_role_id__job_role"] if item["employee_id__employee_work_info__job_role_id__job_role"] else "-",
"Work Type": item["employee_id__employee_work_info__work_type_id__work_type"] if item["employee_id__employee_work_info__work_type_id__work_type"] else "-",
"Shift": item["employee_id__employee_work_info__shift_id__employee_shift"] if item["employee_id__employee_work_info__shift_id__employee_shift"] else "-",
"Department": (
item[
"employee_id__employee_work_info__department_id__department"
]
if item[
"employee_id__employee_work_info__department_id__department"
]
else "-"
),
"Job Position": (
item[
"employee_id__employee_work_info__job_position_id__job_position"
]
if item[
"employee_id__employee_work_info__job_position_id__job_position"
]
else "-"
),
"Job Role": (
item["employee_id__employee_work_info__job_role_id__job_role"]
if item[
"employee_id__employee_work_info__job_role_id__job_role"
]
else "-"
),
"Work Type": (
item["employee_id__employee_work_info__work_type_id__work_type"]
if item[
"employee_id__employee_work_info__work_type_id__work_type"
]
else "-"
),
"Shift": (
item[
"employee_id__employee_work_info__shift_id__employee_shift"
]
if item[
"employee_id__employee_work_info__shift_id__employee_shift"
]
else "-"
),
"Experience": item["employee_id__employee_work_info__experience"],
"Leave Type": item["leave_type_id__name"],
"Start Date": item["start_date"],
"Start Date Breakdown": BREAKDOWN_MAP.get(item["start_date_breakdown"], "-"),
"End Date Breakdown": BREAKDOWN_MAP.get(item["end_date_breakdown"], "-"),
"Start Date Breakdown": BREAKDOWN_MAP.get(
item["start_date_breakdown"], "-"
),
"End Date Breakdown": BREAKDOWN_MAP.get(
item["end_date_breakdown"], "-"
),
"End Date": item["end_date"],
"Requested Days": item["requested_days"],
"Status": LEAVE_STATUS.get(item["status"]),
"Company":item['employee_id__employee_work_info__company_id__company'],
"Company": item[
"employee_id__employee_work_info__company_id__company"
],
}
for item in data
]
elif model_type == "available_leave":
qs = AvailableLeave.objects.all()
available_leave_filter = AssignedLeaveFilter(request.GET, queryset= qs)
available_leave_filter = AssignedLeaveFilter(request.GET, queryset=qs)
qs = available_leave_filter.qs
data = list(qs.values(
"employee_id__employee_first_name","employee_id__employee_last_name","leave_type_id__name",
"available_days","carryforward_days","total_leave_days","assigned_date","reset_date","expired_date",
'employee_id__gender','employee_id__email','employee_id__phone','employee_id__employee_work_info__department_id__department',
'employee_id__employee_work_info__job_role_id__job_role','employee_id__employee_work_info__job_position_id__job_position',
'employee_id__employee_work_info__employee_type_id__employee_type','employee_id__employee_work_info__experience',
'employee_id__employee_work_info__work_type_id__work_type','employee_id__employee_work_info__shift_id__employee_shift',
'employee_id__employee_work_info__company_id__company',
))
data = list(
qs.values(
"employee_id__employee_first_name",
"employee_id__employee_last_name",
"leave_type_id__name",
"available_days",
"carryforward_days",
"total_leave_days",
"assigned_date",
"reset_date",
"expired_date",
"employee_id__gender",
"employee_id__email",
"employee_id__phone",
"employee_id__employee_work_info__department_id__department",
"employee_id__employee_work_info__job_role_id__job_role",
"employee_id__employee_work_info__job_position_id__job_position",
"employee_id__employee_work_info__employee_type_id__employee_type",
"employee_id__employee_work_info__experience",
"employee_id__employee_work_info__work_type_id__work_type",
"employee_id__employee_work_info__shift_id__employee_shift",
"employee_id__employee_work_info__company_id__company",
)
)
choice_gender = {
"male": "Male",
"female": "Female",
@@ -110,11 +190,47 @@ if apps.is_installed("leave"):
"Gender": choice_gender.get(item["employee_id__gender"]),
"Email": item["employee_id__email"],
"Phone": item["employee_id__phone"],
"Department": item["employee_id__employee_work_info__department_id__department"] if item["employee_id__employee_work_info__department_id__department"] else "-",
"Job Position": item["employee_id__employee_work_info__job_position_id__job_position"] if item["employee_id__employee_work_info__job_position_id__job_position"] else "-",
"Job Role": item["employee_id__employee_work_info__job_role_id__job_role"] if item["employee_id__employee_work_info__job_role_id__job_role"] else "-",
"Work Type": item["employee_id__employee_work_info__work_type_id__work_type"] if item["employee_id__employee_work_info__work_type_id__work_type"] else "-",
"Shift": item["employee_id__employee_work_info__shift_id__employee_shift"] if item["employee_id__employee_work_info__shift_id__employee_shift"] else "-",
"Department": (
item[
"employee_id__employee_work_info__department_id__department"
]
if item[
"employee_id__employee_work_info__department_id__department"
]
else "-"
),
"Job Position": (
item[
"employee_id__employee_work_info__job_position_id__job_position"
]
if item[
"employee_id__employee_work_info__job_position_id__job_position"
]
else "-"
),
"Job Role": (
item["employee_id__employee_work_info__job_role_id__job_role"]
if item[
"employee_id__employee_work_info__job_role_id__job_role"
]
else "-"
),
"Work Type": (
item["employee_id__employee_work_info__work_type_id__work_type"]
if item[
"employee_id__employee_work_info__work_type_id__work_type"
]
else "-"
),
"Shift": (
item[
"employee_id__employee_work_info__shift_id__employee_shift"
]
if item[
"employee_id__employee_work_info__shift_id__employee_shift"
]
else "-"
),
"Experience": item["employee_id__employee_work_info__experience"],
"Leave Type": item["leave_type_id__name"],
"Available Days": item["available_days"],
@@ -123,7 +239,9 @@ if apps.is_installed("leave"):
"Assigned Date": item["assigned_date"],
"Reset Date": item.get("reset_date", "-") or "-",
"Expired Date": item.get("expired_date", "-") or "-",
"Company":item['employee_id__employee_work_info__company_id__company'],
"Company": item[
"employee_id__employee_work_info__company_id__company"
],
}
for item in data
]

View File

@@ -1,7 +1,7 @@
from django.apps import apps
from django.http import JsonResponse
from django.shortcuts import render
from django.utils.dateparse import parse_date
from django.apps import apps
if apps.is_installed("payroll"):
@@ -10,30 +10,35 @@ if apps.is_installed("payroll"):
from payroll.filters import PayslipFilter
from payroll.models.models import Payslip
@login_required
@permission_required(perm="payroll.view_payslip")
def payroll_report(request):
company = 'all'
company = "all"
selected_company = request.session.get("selected_company")
if selected_company != 'all':
if selected_company != "all":
company = Company.objects.filter(id=selected_company).first()
if request.user.has_perm("payroll.view_payslip"):
payslips = Payslip.objects.all()
else:
payslips = Payslip.objects.filter(employee_id__employee_user_id=request.user)
payslips = Payslip.objects.filter(
employee_id__employee_user_id=request.user
)
filter_form = PayslipFilter(request.GET, payslips)
return render(request, "report/payroll_report.html",{'company':company,"f":filter_form})
return render(
request,
"report/payroll_report.html",
{"company": company, "f": filter_form},
)
@login_required
@permission_required(perm="payroll.view_payslip")
def payroll_pivot(request):
model_type = request.GET.get("model", "payslip")
if model_type == 'payslip':
if model_type == "payslip":
qs = Payslip.objects.all()
if employee_id := request.GET.getlist("employee_id"):
@@ -56,7 +61,7 @@ if apps.is_installed("payroll"):
qs = qs.filter(end_date__gte=end_date_from)
if end_date_to:
qs = qs.filter(end_date__lte=end_date_to)
# Gross Pay Range
gross_pay_gte = request.GET.get("gross_pay__gte")
gross_pay_lte = request.GET.get("gross_pay__lte")
@@ -81,16 +86,32 @@ if apps.is_installed("payroll"):
if net_pay_lte:
qs = qs.filter(net_pay__lte=net_pay_lte)
data = list(qs.values(
'id', # Include payslip ID to fetch pay_head_data later
'employee_id__employee_first_name', 'employee_id__employee_last_name', 'employee_id__gender', 'employee_id__email',
'employee_id__phone', 'start_date', 'end_date', 'contract_wage', 'basic_pay', 'gross_pay', 'deduction', 'net_pay','group_name',
'status', 'employee_id__employee_work_info__department_id__department', 'employee_id__employee_work_info__job_role_id__job_role',
'employee_id__employee_work_info__job_position_id__job_position', 'employee_id__employee_work_info__work_type_id__work_type',
'employee_id__employee_work_info__shift_id__employee_shift', 'employee_id__employee_work_info__employee_type_id__employee_type',
'employee_id__employee_work_info__experience',
))
data = list(
qs.values(
"id", # Include payslip ID to fetch pay_head_data later
"employee_id__employee_first_name",
"employee_id__employee_last_name",
"employee_id__gender",
"employee_id__email",
"employee_id__phone",
"start_date",
"end_date",
"contract_wage",
"basic_pay",
"gross_pay",
"deduction",
"net_pay",
"group_name",
"status",
"employee_id__employee_work_info__department_id__department",
"employee_id__employee_work_info__job_role_id__job_role",
"employee_id__employee_work_info__job_position_id__job_position",
"employee_id__employee_work_info__work_type_id__work_type",
"employee_id__employee_work_info__shift_id__employee_shift",
"employee_id__employee_work_info__employee_type_id__employee_type",
"employee_id__employee_work_info__experience",
)
)
choice_gender = {
"male": "Male",
@@ -102,12 +123,16 @@ if apps.is_installed("payroll"):
"draft": "Draft",
"review_ongoing": "Review Ongoing",
"confirmed": "Confirmed",
"paid": "Paid"
"paid": "Paid",
}
# Fetch pay_head_data separately and map by payslip ID
payslip_ids = [item["id"] for item in data]
pay_head_data_dict = dict(Payslip.objects.filter(id__in=payslip_ids).values_list("id", "pay_head_data"))
pay_head_data_dict = dict(
Payslip.objects.filter(id__in=payslip_ids).values_list(
"id", "pay_head_data"
)
)
data_list = []
for item in data:
@@ -116,59 +141,136 @@ if apps.is_installed("payroll"):
# Extract allowances and deductions
allowances = pay_head_data.get("allowances", [])
deductions = (
pay_head_data.get("pretax_deductions", []) + pay_head_data.get("post_tax_deductions", [])
)
deductions = pay_head_data.get(
"pretax_deductions", []
) + pay_head_data.get("post_tax_deductions", [])
# Prepare allowance and deduction lists with properly rounded amounts
allowance_titles = ", ".join([allowance["title"] for allowance in allowances]) or "-"
allowance_amounts = ", ".join(
[str(round(float(allowance["amount"] or 0), 2)) for allowance in allowances]
) or "-"
allowance_titles = (
", ".join([allowance["title"] for allowance in allowances]) or "-"
)
allowance_amounts = (
", ".join(
[
str(round(float(allowance["amount"] or 0), 2))
for allowance in allowances
]
)
or "-"
)
deduction_titles = ", ".join([deduction["title"] for deduction in deductions]) or "-"
deduction_amounts = ", ".join(
[str(round(float(deduction["amount"] or 0), 2)) for deduction in deductions]
) or "-"
deduction_titles = (
", ".join([deduction["title"] for deduction in deductions]) or "-"
)
deduction_amounts = (
", ".join(
[
str(round(float(deduction["amount"] or 0), 2))
for deduction in deductions
]
)
or "-"
)
# Calculate total allowance amount
total_allowance_amount = sum(
[round(float(allowance["amount"] or 0), 2) for allowance in allowances]
[
round(float(allowance["amount"] or 0), 2)
for allowance in allowances
]
)
# Calculate total deduction amount
total_deduction_amount = sum(
[round(float(deduction["amount"] or 0), 2) for deduction in deductions]
[
round(float(deduction["amount"] or 0), 2)
for deduction in deductions
]
)
# Main data structure
data_list.append({
"Employee": f"{item['employee_id__employee_first_name']} {item['employee_id__employee_last_name']}",
"Gender": choice_gender.get(item["employee_id__gender"]),
"Email": item["employee_id__email"],
"Phone": item["employee_id__phone"],
"Department": item["employee_id__employee_work_info__department_id__department"] if item["employee_id__employee_work_info__department_id__department"] else "-",
"Job Position": item["employee_id__employee_work_info__job_position_id__job_position"] if item["employee_id__employee_work_info__job_position_id__job_position"] else "-",
"Job Role": item["employee_id__employee_work_info__job_role_id__job_role"] if item["employee_id__employee_work_info__job_role_id__job_role"] else "-",
"Work Type": item["employee_id__employee_work_info__work_type_id__work_type"] if item["employee_id__employee_work_info__work_type_id__work_type"] else "-",
"Shift": item["employee_id__employee_work_info__shift_id__employee_shift"] if item["employee_id__employee_work_info__shift_id__employee_shift"] else "-",
"Employee Type": item["employee_id__employee_work_info__employee_type_id__employee_type"] if item["employee_id__employee_work_info__employee_type_id__employee_type"] else "-",
"Payslip Start Date": item["start_date"],
"Payslip End Date": item["end_date"],
"Batch Name": item['group_name'] if item['group_name'] else '-',
"Contract Wage": round(float(item["contract_wage"] or 0), 2),
"Basic Salary": round(float(item["basic_pay"] or 0), 2),
"Gross Pay": round(float(item["gross_pay"] or 0), 2),
"Net Pay": round(float(item["net_pay"] or 0), 2),
"Allowance Title": allowance_titles,
"Allowance Amount": allowance_amounts,
"Total Allowance Amount": round(total_allowance_amount, 2),
"Deduction Title": deduction_titles,
"Deduction Amount": deduction_amounts,
"Total Deduction Amount": round(total_deduction_amount, 2),
"Status": STATUS.get(item["status"]),
"Experience": round(float(item["employee_id__employee_work_info__experience"] or 0), 2),
})
data_list.append(
{
"Employee": f"{item['employee_id__employee_first_name']} {item['employee_id__employee_last_name']}",
"Gender": choice_gender.get(item["employee_id__gender"]),
"Email": item["employee_id__email"],
"Phone": item["employee_id__phone"],
"Department": (
item[
"employee_id__employee_work_info__department_id__department"
]
if item[
"employee_id__employee_work_info__department_id__department"
]
else "-"
),
"Job Position": (
item[
"employee_id__employee_work_info__job_position_id__job_position"
]
if item[
"employee_id__employee_work_info__job_position_id__job_position"
]
else "-"
),
"Job Role": (
item[
"employee_id__employee_work_info__job_role_id__job_role"
]
if item[
"employee_id__employee_work_info__job_role_id__job_role"
]
else "-"
),
"Work Type": (
item[
"employee_id__employee_work_info__work_type_id__work_type"
]
if item[
"employee_id__employee_work_info__work_type_id__work_type"
]
else "-"
),
"Shift": (
item[
"employee_id__employee_work_info__shift_id__employee_shift"
]
if item[
"employee_id__employee_work_info__shift_id__employee_shift"
]
else "-"
),
"Employee Type": (
item[
"employee_id__employee_work_info__employee_type_id__employee_type"
]
if item[
"employee_id__employee_work_info__employee_type_id__employee_type"
]
else "-"
),
"Payslip Start Date": item["start_date"],
"Payslip End Date": item["end_date"],
"Batch Name": item["group_name"] if item["group_name"] else "-",
"Contract Wage": round(float(item["contract_wage"] or 0), 2),
"Basic Salary": round(float(item["basic_pay"] or 0), 2),
"Gross Pay": round(float(item["gross_pay"] or 0), 2),
"Net Pay": round(float(item["net_pay"] or 0), 2),
"Allowance Title": allowance_titles,
"Allowance Amount": allowance_amounts,
"Total Allowance Amount": round(total_allowance_amount, 2),
"Deduction Title": deduction_titles,
"Deduction Amount": deduction_amounts,
"Total Deduction Amount": round(total_deduction_amount, 2),
"Status": STATUS.get(item["status"]),
"Experience": round(
float(
item["employee_id__employee_work_info__experience"] or 0
),
2,
),
}
)
elif model_type == "allowance":
@@ -177,13 +279,24 @@ if apps.is_installed("payroll"):
payslip_filter = PayslipFilter(request.GET, queryset=payslips)
filtered_qs = payslip_filter.qs # This uses all custom filters you defined
data = list(filtered_qs.values(
'id', # Include payslip ID to fetch pay_head_data later
'employee_id__employee_first_name', 'employee_id__employee_last_name', 'employee_id__gender', 'employee_id__email',
'employee_id__phone', 'start_date', 'end_date','status', 'employee_id__employee_work_info__department_id__department',
'employee_id__employee_work_info__job_role_id__job_role','employee_id__employee_work_info__job_position_id__job_position',
'employee_id__employee_work_info__work_type_id__work_type','employee_id__employee_work_info__shift_id__employee_shift',
))
data = list(
filtered_qs.values(
"id", # Include payslip ID to fetch pay_head_data later
"employee_id__employee_first_name",
"employee_id__employee_last_name",
"employee_id__gender",
"employee_id__email",
"employee_id__phone",
"start_date",
"end_date",
"status",
"employee_id__employee_work_info__department_id__department",
"employee_id__employee_work_info__job_role_id__job_role",
"employee_id__employee_work_info__job_position_id__job_position",
"employee_id__employee_work_info__work_type_id__work_type",
"employee_id__employee_work_info__shift_id__employee_shift",
)
)
choice_gender = {
"male": "Male",
@@ -195,12 +308,16 @@ if apps.is_installed("payroll"):
"draft": "Draft",
"review_ongoing": "Review Ongoing",
"confirmed": "Confirmed",
"paid": "Paid"
"paid": "Paid",
}
# Fetch pay_head_data separately and map by payslip ID
payslip_ids = [item["id"] for item in data]
pay_head_data_dict = dict(Payslip.objects.filter(id__in=payslip_ids).values_list("id", "pay_head_data"))
pay_head_data_dict = dict(
Payslip.objects.filter(id__in=payslip_ids).values_list(
"id", "pay_head_data"
)
)
data_list = []
for item in data:
@@ -212,43 +329,88 @@ if apps.is_installed("payroll"):
# Add Allowances to combined data
for allowance in pay_head_data.get("allowances", []):
all_pay_data.append({
"Pay Type": "Allowance",
"Title": allowance["title"],
"Amount": round(float(allowance["amount"] or 0), 2),
})
all_pay_data.append(
{
"Pay Type": "Allowance",
"Title": allowance["title"],
"Amount": round(float(allowance["amount"] or 0), 2),
}
)
# Add Deductions to combined data
for deduction in (
pay_head_data.get("pretax_deductions", []) + pay_head_data.get("post_tax_deductions", [])
):
all_pay_data.append({
"Pay Type": "Deduction",
"Title": deduction["title"],
"Amount": round(float(deduction["amount"] or 0), 2),
})
for deduction in pay_head_data.get(
"pretax_deductions", []
) + pay_head_data.get("post_tax_deductions", []):
all_pay_data.append(
{
"Pay Type": "Deduction",
"Title": deduction["title"],
"Amount": round(float(deduction["amount"] or 0), 2),
}
)
# Add combined data to main data list
for pay_item in all_pay_data:
data_list.append({
"Employee": f"{item['employee_id__employee_first_name']} {item['employee_id__employee_last_name']}",
"Gender": choice_gender.get(item["employee_id__gender"]),
"Email": item["employee_id__email"],
"Phone": item["employee_id__phone"],
"Department": item["employee_id__employee_work_info__department_id__department"] if item["employee_id__employee_work_info__department_id__department"] else "-",
"Job Position": item["employee_id__employee_work_info__job_position_id__job_position"] if item["employee_id__employee_work_info__job_position_id__job_position"] else "-",
"Job Role": item["employee_id__employee_work_info__job_role_id__job_role"] if item["employee_id__employee_work_info__job_role_id__job_role"] else "-",
"Work Type": item["employee_id__employee_work_info__work_type_id__work_type"] if item["employee_id__employee_work_info__work_type_id__work_type"] else "-",
"Shift": item["employee_id__employee_work_info__shift_id__employee_shift"] if item["employee_id__employee_work_info__shift_id__employee_shift"] else "-",
"Payslip Start Date": item["start_date"],
"Payslip End Date": item["end_date"],
"Allowance & Deduction": pay_item["Pay Type"],
"Allowance & Deduction Title": pay_item["Title"],
"Allowance & Deduction Amount": pay_item["Amount"],
"Status": STATUS.get(item["status"]),
})
data_list.append(
{
"Employee": f"{item['employee_id__employee_first_name']} {item['employee_id__employee_last_name']}",
"Gender": choice_gender.get(item["employee_id__gender"]),
"Email": item["employee_id__email"],
"Phone": item["employee_id__phone"],
"Department": (
item[
"employee_id__employee_work_info__department_id__department"
]
if item[
"employee_id__employee_work_info__department_id__department"
]
else "-"
),
"Job Position": (
item[
"employee_id__employee_work_info__job_position_id__job_position"
]
if item[
"employee_id__employee_work_info__job_position_id__job_position"
]
else "-"
),
"Job Role": (
item[
"employee_id__employee_work_info__job_role_id__job_role"
]
if item[
"employee_id__employee_work_info__job_role_id__job_role"
]
else "-"
),
"Work Type": (
item[
"employee_id__employee_work_info__work_type_id__work_type"
]
if item[
"employee_id__employee_work_info__work_type_id__work_type"
]
else "-"
),
"Shift": (
item[
"employee_id__employee_work_info__shift_id__employee_shift"
]
if item[
"employee_id__employee_work_info__shift_id__employee_shift"
]
else "-"
),
"Payslip Start Date": item["start_date"],
"Payslip End Date": item["end_date"],
"Allowance & Deduction": pay_item["Pay Type"],
"Allowance & Deduction Title": pay_item["Title"],
"Allowance & Deduction Amount": pay_item["Amount"],
"Status": STATUS.get(item["status"]),
}
)
else:
data_list = []
return JsonResponse(data_list, safe=False)

View File

@@ -1,6 +1,6 @@
from django.apps import apps
from django.http import JsonResponse
from django.shortcuts import render
from django.apps import apps
if apps.is_installed("pms"):
@@ -10,22 +10,23 @@ if apps.is_installed("pms"):
from pms.models import EmployeeKeyResult, EmployeeObjective, Feedback, Objective
from pms.views import objective_filter_pagination
@login_required
@permission_required(perm="pms.view_objective")
def pms_report(request):
company = 'all'
company = "all"
selected_company = request.session.get("selected_company")
if selected_company != 'all':
if selected_company != "all":
company = Company.objects.filter(id=selected_company).first()
employee = request.user.employee_get
objective_own = EmployeeObjective.objects.filter(
employee_id=employee, archive=False
employee_id=employee, archive=False
)
objective_own = objective_own.distinct()
feedback = request.GET.get("search") # if the search is none the filter will works
feedback = request.GET.get(
"search"
) # if the search is none the filter will works
if feedback is None:
feedback = ""
self_feedback = Feedback.objects.filter(employee_id=employee).filter(
@@ -37,17 +38,21 @@ if apps.is_installed("pms"):
)
context = objective_filter_pagination(request, objective_own)
cm = {'company':company,"feedback_filter_form":feedback_filter_own.form,"emp_obj_form": EmployeeObjectiveFilter()}
cm = {
"company": company,
"feedback_filter_form": feedback_filter_own.form,
"emp_obj_form": EmployeeObjectiveFilter(),
}
context.update(cm)
return render(request, "report/pms_report.html",context)
return render(request, "report/pms_report.html", context)
@login_required
@permission_required(perm="pms.view_objective")
def pms_pivot(request):
model_type = request.GET.get('model', 'objective')
if model_type == 'objective':
model_type = request.GET.get("model", "objective")
if model_type == "objective":
qs = Objective.objects.all()
if managers := request.GET.getlist("managers"):
@@ -59,41 +64,74 @@ if apps.is_installed("pms"):
if key_result_id := request.GET.get("employee_objective__key_result_id"):
qs = qs.filter(key_result_id=key_result_id)
data = list(qs.values(
"title","managers__employee_first_name","managers__employee_last_name",
"assignees__employee_first_name","assignees__employee_last_name",
"key_result_id__title","key_result_id__target_value","duration_unit","duration",
"company_id__company","key_result_id__progress_type","key_result_id__duration",
'assignees__employee_work_info__department_id__department', 'assignees__employee_work_info__job_role_id__job_role',
'assignees__employee_work_info__job_position_id__job_position',
))
data = list(
qs.values(
"title",
"managers__employee_first_name",
"managers__employee_last_name",
"assignees__employee_first_name",
"assignees__employee_last_name",
"key_result_id__title",
"key_result_id__target_value",
"duration_unit",
"duration",
"company_id__company",
"key_result_id__progress_type",
"key_result_id__duration",
"assignees__employee_work_info__department_id__department",
"assignees__employee_work_info__job_role_id__job_role",
"assignees__employee_work_info__job_position_id__job_position",
)
)
DURATION_UNIT = {
"days" :"Days",
"months" :"Months",
"years" :"Years",
"days": "Days",
"months": "Months",
"years": "Years",
}
KEY_RESULT_TARGET = {
"%" :"%",
"#" :"Number",
"Currency" :"Currency",
"%": "%",
"#": "Number",
"Currency": "Currency",
}
data_list = [
{
"Objective":item["title"],
"Objective Duration":f'{item["duration"]} {DURATION_UNIT.get(item["duration_unit"])}',
"Manager":f"{item['managers__employee_first_name']} {item['managers__employee_last_name']}" if item['managers__employee_first_name'] else "-",
"Assignees":f"{item['assignees__employee_first_name']} {item['assignees__employee_last_name']}",
"Assignee Department":item["assignees__employee_work_info__department_id__department"] if item["assignees__employee_work_info__department_id__department"] else "-",
"Assignee Job Position":item["assignees__employee_work_info__job_position_id__job_position"] if item["assignees__employee_work_info__job_position_id__job_position"] else "-",
"Assignee Job Role":item["assignees__employee_work_info__job_role_id__job_role"] if item["assignees__employee_work_info__job_role_id__job_role"] else"-",
"Key Results":item["key_result_id__title"],
"Key Result Duration":f'{item["key_result_id__duration"]} {"Days"}',
"Key Result Target":f'{item["key_result_id__target_value"]} {KEY_RESULT_TARGET.get(item["key_result_id__progress_type"])}',
"Company":item["company_id__company"]
}for item in data
"Objective": item["title"],
"Objective Duration": f'{item["duration"]} {DURATION_UNIT.get(item["duration_unit"])}',
"Manager": (
f"{item['managers__employee_first_name']} {item['managers__employee_last_name']}"
if item["managers__employee_first_name"]
else "-"
),
"Assignees": f"{item['assignees__employee_first_name']} {item['assignees__employee_last_name']}",
"Assignee Department": (
item["assignees__employee_work_info__department_id__department"]
if item[
"assignees__employee_work_info__department_id__department"
]
else "-"
),
"Assignee Job Position": (
item[
"assignees__employee_work_info__job_position_id__job_position"
]
if item[
"assignees__employee_work_info__job_position_id__job_position"
]
else "-"
),
"Assignee Job Role": (
item["assignees__employee_work_info__job_role_id__job_role"]
if item["assignees__employee_work_info__job_role_id__job_role"]
else "-"
),
"Key Results": item["key_result_id__title"],
"Key Result Duration": f'{item["key_result_id__duration"]} {"Days"}',
"Key Result Target": f'{item["key_result_id__target_value"]} {KEY_RESULT_TARGET.get(item["key_result_id__progress_type"])}',
"Company": item["company_id__company"],
}
for item in data
]
elif model_type == 'feedback':
elif model_type == "feedback":
data_list = []
@@ -106,13 +144,13 @@ if apps.is_installed("pms"):
feedbacks = Feedback.objects.select_related(
"manager_id", "employee_id", "question_template_id"
).prefetch_related(
"colleague_id", "subordinate_id",
"colleague_id",
"subordinate_id",
"question_template_id__question",
"feedback_answer__question_id", # related_name
"feedback_answer__employee_id",
)
# ✅ FILTERS added here
if review_cycle := request.GET.get("review_cycle"):
feedbacks = feedbacks.filter(review_cycle=review_cycle)
@@ -131,63 +169,102 @@ if apps.is_installed("pms"):
if end_date := request.GET.get("end_date"):
feedbacks = feedbacks.filter(created_at__date__lte=end_date)
for feedback in feedbacks:
manager = f"{feedback.manager_id.employee_first_name} {feedback.manager_id.employee_last_name}" if feedback.manager_id else ""
employee = f"{feedback.employee_id.employee_first_name} {feedback.employee_id.employee_last_name}" if feedback.employee_id else ""
manager = (
f"{feedback.manager_id.employee_first_name} {feedback.manager_id.employee_last_name}"
if feedback.manager_id
else ""
)
employee = (
f"{feedback.employee_id.employee_first_name} {feedback.employee_id.employee_last_name}"
if feedback.employee_id
else ""
)
answerable_employees = list(feedback.colleague_id.all()) + list(feedback.subordinate_id.all())
answerable_names = ', '.join(
f"{e.employee_first_name} {e.employee_last_name}" for e in answerable_employees
) or "-"
answerable_employees = list(feedback.colleague_id.all()) + list(
feedback.subordinate_id.all()
)
answerable_names = (
", ".join(
f"{e.employee_first_name} {e.employee_last_name}"
for e in answerable_employees
)
or "-"
)
questions = feedback.question_template_id.question.all()
# Fetch ALL answers for this feedback and map them grouped by question
answers = feedback.feedback_answer.select_related("employee_id", "question_id")
answers = feedback.feedback_answer.select_related(
"employee_id", "question_id"
)
for question in questions:
question_answers = [ans for ans in answers if ans.question_id_id == question.id]
question_answers = [
ans for ans in answers if ans.question_id_id == question.id
]
# If no one answered this question, still show the question
if not question_answers:
data_list.append({
"Title":feedback.review_cycle,
"Manager": manager,
"Employee": employee,
"Answerable Employees": answerable_names,
"Questions": question.question,
"Answer": "",
"Answered Employees": "-",
"Status": feedback.status,
"Start Date": feedback.start_date,
"End Date": feedback.end_date,
"Is Cyclic": "Yes" if feedback.cyclic_feedback else "No",
"Cycle Period": f"{feedback.cyclic_feedback_days_count} {PERIOD.get(feedback.cyclic_feedback_period)}" if feedback.cyclic_feedback_days_count else "-"
})
else:
for answer in question_answers:
answer_value = answer.answer.get("answer") if answer.answer else ""
answered_by = f"{answer.employee_id.employee_first_name} {answer.employee_id.employee_last_name}" if answer.employee_id else "-"
data_list.append({
"Title":feedback.review_cycle,
data_list.append(
{
"Title": feedback.review_cycle,
"Manager": manager,
"Employee": employee,
"Answerable Employees": answerable_names,
"Questions": question.question,
"Answer": answer_value,
"Answered Employees": answered_by,
"Answer": "",
"Answered Employees": "-",
"Status": feedback.status,
"Start Date": feedback.start_date,
"End Date": feedback.end_date,
"Is Cyclic": "Yes" if feedback.cyclic_feedback else "No",
"Cycle Period": f"{feedback.cyclic_feedback_days_count} {PERIOD.get(feedback.cyclic_feedback_period)}" if feedback.cyclic_feedback_days_count else "-"
})
elif model_type == 'employeeobjective':
"Is Cyclic": (
"Yes" if feedback.cyclic_feedback else "No"
),
"Cycle Period": (
f"{feedback.cyclic_feedback_days_count} {PERIOD.get(feedback.cyclic_feedback_period)}"
if feedback.cyclic_feedback_days_count
else "-"
),
}
)
else:
for answer in question_answers:
answer_value = (
answer.answer.get("answer") if answer.answer else ""
)
answered_by = (
f"{answer.employee_id.employee_first_name} {answer.employee_id.employee_last_name}"
if answer.employee_id
else "-"
)
data_list.append(
{
"Title": feedback.review_cycle,
"Manager": manager,
"Employee": employee,
"Answerable Employees": answerable_names,
"Questions": question.question,
"Answer": answer_value,
"Answered Employees": answered_by,
"Status": feedback.status,
"Start Date": feedback.start_date,
"End Date": feedback.end_date,
"Is Cyclic": (
"Yes" if feedback.cyclic_feedback else "No"
),
"Cycle Period": (
f"{feedback.cyclic_feedback_days_count} {PERIOD.get(feedback.cyclic_feedback_period)}"
if feedback.cyclic_feedback_days_count
else "-"
),
}
)
elif model_type == "employeeobjective":
from django.utils.dateparse import parse_date
qs=EmployeeKeyResult.objects.all()
qs = EmployeeKeyResult.objects.all()
# Filter section
if assignees := request.GET.getlist("employee_id"):
@@ -211,44 +288,87 @@ if apps.is_installed("pms"):
if end_date_to:
qs = qs.filter(end_date__lte=end_date_to)
data = list(qs.values(
"key_result","employee_objective_id__employee_id__employee_first_name","employee_objective_id__employee_id__employee_last_name",
"employee_objective_id__objective_id__title","employee_objective_id__objective_id__duration_unit","employee_objective_id__objective_id__duration",
"start_value","current_value","target_value","start_date","end_date","status","progress_type",'employee_objective_id__employee_id__employee_work_info__department_id__department',
'employee_objective_id__employee_id__employee_work_info__job_role_id__job_role','employee_objective_id__employee_id__employee_work_info__job_position_id__job_position',
))
data = list(
qs.values(
"key_result",
"employee_objective_id__employee_id__employee_first_name",
"employee_objective_id__employee_id__employee_last_name",
"employee_objective_id__objective_id__title",
"employee_objective_id__objective_id__duration_unit",
"employee_objective_id__objective_id__duration",
"start_value",
"current_value",
"target_value",
"start_date",
"end_date",
"status",
"progress_type",
"employee_objective_id__employee_id__employee_work_info__department_id__department",
"employee_objective_id__employee_id__employee_work_info__job_role_id__job_role",
"employee_objective_id__employee_id__employee_work_info__job_position_id__job_position",
)
)
DURATION_UNIT = {
"days" :"Days",
"months" :"Months",
"years" :"Years",
"days": "Days",
"months": "Months",
"years": "Years",
}
KEY_RESULT_TARGET = {
"%" :"%",
"#" :"Number",
"Currency" :"Currency",
"%": "%",
"#": "Number",
"Currency": "Currency",
}
data_list = [
{
"Employee": f"{item['employee_objective_id__employee_id__employee_first_name']} {item['employee_objective_id__employee_id__employee_last_name']}",
"Department":item["employee_objective_id__employee_id__employee_work_info__department_id__department"] if item["employee_objective_id__employee_id__employee_work_info__department_id__department"] else "-",
"Job Position":item["employee_objective_id__employee_id__employee_work_info__job_position_id__job_position"] if item["employee_objective_id__employee_id__employee_work_info__job_position_id__job_position"] else "-",
"Job Role":item["employee_objective_id__employee_id__employee_work_info__job_role_id__job_role"] if item["employee_objective_id__employee_id__employee_work_info__job_role_id__job_role"] else "-",
"Employee Keyresult":item["key_result"],
"Objective":item["employee_objective_id__objective_id__title"],
"Objective Duration":f'{item["employee_objective_id__objective_id__duration"]} {DURATION_UNIT.get(item["employee_objective_id__objective_id__duration_unit"])}',
"Keyresult Start Value":f'{item["start_value"]} {KEY_RESULT_TARGET.get(item["progress_type"])}',
"Keyresult Target Value":f'{item["target_value"]} {KEY_RESULT_TARGET.get(item["progress_type"])}',
"Keyresult Current Value":f'{item["current_value"]} {KEY_RESULT_TARGET.get(item["progress_type"])}' if item["current_value"] else "-",
"Keyresult Start Date":item["start_date"] if item["start_date"] else "-",
"Keyresult End Date":item["end_date"] if item["end_date"] else "-",
"status":item["status"],
}for item in data
"Department": (
item[
"employee_objective_id__employee_id__employee_work_info__department_id__department"
]
if item[
"employee_objective_id__employee_id__employee_work_info__department_id__department"
]
else "-"
),
"Job Position": (
item[
"employee_objective_id__employee_id__employee_work_info__job_position_id__job_position"
]
if item[
"employee_objective_id__employee_id__employee_work_info__job_position_id__job_position"
]
else "-"
),
"Job Role": (
item[
"employee_objective_id__employee_id__employee_work_info__job_role_id__job_role"
]
if item[
"employee_objective_id__employee_id__employee_work_info__job_role_id__job_role"
]
else "-"
),
"Employee Keyresult": item["key_result"],
"Objective": item["employee_objective_id__objective_id__title"],
"Objective Duration": f'{item["employee_objective_id__objective_id__duration"]} {DURATION_UNIT.get(item["employee_objective_id__objective_id__duration_unit"])}',
"Keyresult Start Value": f'{item["start_value"]} {KEY_RESULT_TARGET.get(item["progress_type"])}',
"Keyresult Target Value": f'{item["target_value"]} {KEY_RESULT_TARGET.get(item["progress_type"])}',
"Keyresult Current Value": (
f'{item["current_value"]} {KEY_RESULT_TARGET.get(item["progress_type"])}'
if item["current_value"]
else "-"
),
"Keyresult Start Date": (
item["start_date"] if item["start_date"] else "-"
),
"Keyresult End Date": item["end_date"] if item["end_date"] else "-",
"status": item["status"],
}
for item in data
]
else:
data_list =[]
data_list = []
return JsonResponse(data_list, safe = False)
return JsonResponse(data_list, safe=False)

View File

@@ -1,6 +1,6 @@
from django.apps import apps
from django.http import JsonResponse
from django.shortcuts import render
from django.apps import apps
if apps.is_installed("recruitment"):
@@ -14,15 +14,24 @@ if apps.is_installed("recruitment"):
@login_required
@permission_required(perm="recruitment.view_recruitment")
def recruitment_report(request):
company = 'all'
company = "all"
selected_company = request.session.get("selected_company")
if selected_company != 'all':
if selected_company != "all":
company = Company.objects.filter(id=selected_company).first()
return render(request, "report/recruitment_report.html",{'company':company, "f":CandidateFilter(), "fr":RecruitmentFilter(),"fo":OnboardingStageFilter()})
return render(
request,
"report/recruitment_report.html",
{
"company": company,
"f": CandidateFilter(),
"fr": RecruitmentFilter(),
"fo": OnboardingStageFilter(),
},
)
@login_required
@permission_required(perm="recruitment.view_recruitment")
def recruitment_pivot(request):
def recruitment_pivot(request):
model_type = request.GET.get("model", "candidate") # Default to Candidate
if model_type == "candidate":
@@ -30,97 +39,157 @@ if apps.is_installed("recruitment"):
filter_obj = CandidateFilter(request.GET, queryset=qs)
qs = filter_obj.qs
data = list(qs.values(
"name","recruitment_id__title","job_position_id__job_position","stage_id__stage","email","mobile",
"gender","offer_letter_status","recruitment_id__closed","recruitment_id__vacancy","country",
"recruitment_id__company_id__company","address","dob","state","city","source","job_position_id__department_id__department"
))
data = list(
qs.values(
"name",
"recruitment_id__title",
"job_position_id__job_position",
"stage_id__stage",
"email",
"mobile",
"gender",
"offer_letter_status",
"recruitment_id__closed",
"recruitment_id__vacancy",
"country",
"recruitment_id__company_id__company",
"address",
"dob",
"state",
"city",
"source",
"job_position_id__department_id__department",
)
)
choice_gender = {
"male": "Male",
"female": "Female",
"other": "Other",
}
OFFER_LETTER_STATUS = {
"not_sent" : "Not Sent",
"sent" : "Sent",
"accepted" : "Accepted",
"rejected" : "Rejected",
"joined" : "Joined",
"not_sent": "Not Sent",
"sent": "Sent",
"accepted": "Accepted",
"rejected": "Rejected",
"joined": "Joined",
}
SOURCE_CHOICE = {
"application":"Application Form",
"software":"Inside Software",
"other":"Other",
"application": "Application Form",
"software": "Inside Software",
"other": "Other",
}
data_list = [
{
"Candidate":item["name"],
"Email":item["email"],
"Phone":item["mobile"],
"Gender":choice_gender.get(item["gender"]),
"Address":item["address"],
"Date Of Birth":item["dob"],
"Country":item["country"] if item["country"] else "-",
"State":item["state"] if item["state"] else "-",
"City":item["city"] if item["city"] else "-",
"Source":SOURCE_CHOICE.get(item["source"]) if item["source"] else "-",
"Job Position":item["job_position_id__job_position"],
"Department":item["job_position_id__department_id__department"],
"Offer Letter":OFFER_LETTER_STATUS.get(item["offer_letter_status"]),
"Recruitment":item["recruitment_id__title"],
"Current Stage":item["stage_id__stage"],
"Recruitment Status": 'Closed' if item["recruitment_id__closed"] else 'Open',
"Vacancy" : item["recruitment_id__vacancy"],
"Company" : item["recruitment_id__company_id__company"],
}for item in data
"Candidate": item["name"],
"Email": item["email"],
"Phone": item["mobile"],
"Gender": choice_gender.get(item["gender"]),
"Address": item["address"],
"Date Of Birth": item["dob"],
"Country": item["country"] if item["country"] else "-",
"State": item["state"] if item["state"] else "-",
"City": item["city"] if item["city"] else "-",
"Source": (
SOURCE_CHOICE.get(item["source"]) if item["source"] else "-"
),
"Job Position": item["job_position_id__job_position"],
"Department": item["job_position_id__department_id__department"],
"Offer Letter": OFFER_LETTER_STATUS.get(
item["offer_letter_status"]
),
"Recruitment": item["recruitment_id__title"],
"Current Stage": item["stage_id__stage"],
"Recruitment Status": (
"Closed" if item["recruitment_id__closed"] else "Open"
),
"Vacancy": item["recruitment_id__vacancy"],
"Company": item["recruitment_id__company_id__company"],
}
for item in data
]
elif model_type == "recruitment":
qs = Recruitment.objects.all()
filter_obj = RecruitmentFilter(request.GET, queryset = qs)
filter_obj = RecruitmentFilter(request.GET, queryset=qs)
qs = filter_obj.qs
data = list(qs.values(
"title","vacancy","closed","open_positions__job_position","start_date","end_date","is_published",
"recruitment_managers__employee_first_name","recruitment_managers__employee_last_name","company_id__company",
))
data = list(
qs.values(
"title",
"vacancy",
"closed",
"open_positions__job_position",
"start_date",
"end_date",
"is_published",
"recruitment_managers__employee_first_name",
"recruitment_managers__employee_last_name",
"company_id__company",
)
)
data_list = [
{
"Recruitment" : item["title"],
"Recruitment": item["title"],
"Manager": f"{item['recruitment_managers__employee_first_name']} {item['recruitment_managers__employee_last_name']}",
"Is Closed": 'Closed' if item["closed"] else 'Open',
"Status": 'Published' if item["is_published"] else 'Not Published',
"Start Date":item["start_date"],
"End Date":item["end_date"],
"Job Position":item["open_positions__job_position"],
"Vacancy":item["vacancy"],
"Company" : item["company_id__company"],
}for item in data
"Is Closed": "Closed" if item["closed"] else "Open",
"Status": "Published" if item["is_published"] else "Not Published",
"Start Date": item["start_date"],
"End Date": item["end_date"],
"Job Position": item["open_positions__job_position"],
"Vacancy": item["vacancy"],
"Company": item["company_id__company"],
}
for item in data
]
elif model_type == "onboarding":
qs = OnboardingStage.objects.all()
filter_obj = OnboardingStageFilter(request.GET, queryset = qs)
filter_obj = OnboardingStageFilter(request.GET, queryset=qs)
qs = filter_obj.qs
data = list(qs.values(
"stage_title","recruitment_id__title","employee_id__employee_first_name","employee_id__employee_last_name",
"onboarding_task__task_title",
"onboarding_task__employee_id__employee_first_name","onboarding_task__employee_id__employee_last_name",
"onboarding_task__candidates__name","recruitment_id__company_id__company",
))
data = list(
qs.values(
"stage_title",
"recruitment_id__title",
"employee_id__employee_first_name",
"employee_id__employee_last_name",
"onboarding_task__task_title",
"onboarding_task__employee_id__employee_first_name",
"onboarding_task__employee_id__employee_last_name",
"onboarding_task__candidates__name",
"recruitment_id__company_id__company",
)
)
data_list = [
{
"Recruitment": item["recruitment_id__title"],
"Stage": item["stage_title"],
"Stage Manager": f"{item['employee_id__employee_first_name']} {item['employee_id__employee_last_name']}" if item['employee_id__employee_first_name'] else "-",
"Task": item["onboarding_task__task_title"] if item["onboarding_task__task_title"] else "-",
"Task Manager": f"{item['onboarding_task__employee_id__employee_first_name']} {item['onboarding_task__employee_id__employee_last_name']}" if item['onboarding_task__employee_id__employee_first_name'] else "-",
"Candidates": item["onboarding_task__candidates__name"] if item["onboarding_task__candidates__name"] else "-",
"Company" : item["recruitment_id__company_id__company"] if item["recruitment_id__company_id__company"] else "-",
}for item in data
"Stage Manager": (
f"{item['employee_id__employee_first_name']} {item['employee_id__employee_last_name']}"
if item["employee_id__employee_first_name"]
else "-"
),
"Task": (
item["onboarding_task__task_title"]
if item["onboarding_task__task_title"]
else "-"
),
"Task Manager": (
f"{item['onboarding_task__employee_id__employee_first_name']} {item['onboarding_task__employee_id__employee_last_name']}"
if item["onboarding_task__employee_id__employee_first_name"]
else "-"
),
"Candidates": (
item["onboarding_task__candidates__name"]
if item["onboarding_task__candidates__name"]
else "-"
),
"Company": (
item["recruitment_id__company_id__company"]
if item["recruitment_id__company_id__company"]
else "-"
),
}
for item in data
]
else:
data_list = []