Files
icehrm/web/admin/src/payroll/lib.js
Thilina Pituwala b1df0037db License updated to GPLv3
🧲 New features
Custom user role permissions
Employee edit form updated
Employee daily task list
Attendance and employee distribution charts on dashboard
Improvements to company structure and company assets module
Improved tables for displaying data in several modules
Faster data loading (specially for employee module)
Initials based profile pictures
Re-designed login page
Re-designed user profile page
Improvements to filtering
New REST endpoints for employee qualifications

🐛 Bug fixes
Fixed, issue with managers being able to create performance reviews for employees who are not their direct reports
Fixed, issues related to using full profile image instead of using smaller version of profile image
Changing third gender to other
Improvements and fixes for internal frontend data caching
2020-10-31 19:02:37 +01:00

698 lines
21 KiB
JavaScript

/*
Copyright (c) 2018 [Glacies UG, Berlin, Germany] (http://glacies.de)
Developer: Thilina Hasantha (http://lk.linkedin.com/in/thilinah | https://github.com/thilinah)
*/
/* global modJs, modJsList */
import AdapterBase from '../../../api/AdapterBase';
import TableEditAdapter from '../../../api/TableEditAdapter';
require('codemirror/mode/javascript/javascript');
require('codemirror/addon/edit/closebrackets');
require('codemirror/addon/display/autorefresh');
const CodeMirror = require('codemirror');
/**
* PaydayAdapter
*/
class PaydayAdapter extends AdapterBase {
getDataMapping() {
return [
'id',
'name',
];
}
getHeaders() {
return [
{ sTitle: 'ID', bVisible: false },
{ sTitle: 'Select Pay Frequency' },
];
}
getFormFields() {
return [
['name', { label: 'Name', type: 'text', validation: '' }],
];
}
getAddNewLabel() {
return 'Run Payroll';
}
createTable(elementId) {
$('#payday_all').off();
super.createTable(elementId);
$('#payday_all').off().on('click', function () {
if ($(this).is(':checked')) {
$('.paydayCheck').prop('checked', true);
} else {
$('.paydayCheck').prop('checked', false);
}
});
}
getActionButtonsHtml(id, data) {
const editButton = '<input type="checkbox" class="paydayCheck" id="payday__id_" name="payday__id_" value="checkbox_payday__id_"/>';
let html = '<div style="width:132px;">_edit_</div>';
html = html.replace('_edit_', editButton);
html = html.replace(/_id_/g, id);
html = html.replace(/_BASE_/g, this.baseUrl);
return html;
}
getActionButtonHeader() {
return { sTitle: '<input type="checkbox" id="payday_all" name="payday_all" value="checkbox_payday_all"/>', sClass: 'center' };
}
}
/**
* PayrollAdapter
*/
class PayrollAdapter extends AdapterBase {
getDataMapping() {
return [
'id',
'name',
'pay_period',
'department',
'date_start',
'date_end',
'status',
];
}
getHeaders() {
return [
{ sTitle: 'ID', bVisible: false },
{ sTitle: 'Name' },
{ sTitle: 'Pay Frequency' },
{ sTitle: 'Department' },
{ sTitle: 'Date Start' },
{ sTitle: 'Date End' },
{ sTitle: 'Status' },
];
}
getFormFields() {
return [
['id', { label: 'ID', type: 'hidden' }],
['name', { label: 'Name', type: 'text' }],
['pay_period', {
label: 'Pay Frequency', type: 'select', 'remote-source': ['PayFrequency', 'id', 'name'], sort: 'none',
}],
['deduction_group', {
label: 'Payroll Group', type: 'select', 'remote-source': ['DeductionGroup', 'id', 'name'], sort: 'none',
}],
['payslipTemplate', { label: 'Payslip Template', type: 'select', 'remote-source': ['PayslipTemplate', 'id', 'name'] }],
['department', {
label: 'Department', type: 'select2', 'remote-source': ['CompanyStructure', 'id', 'title'], sort: 'none',
}],
['date_start', { label: 'Start Date', type: 'date', validation: '' }],
['date_end', { label: 'End Date', type: 'date', validation: '' }],
// [ "column_template", {"label":"Report Column Template","type":"select","remote-source":["PayrollColumnTemplate","id","name"]}],
['columns', { label: 'Payroll Columns', type: 'select2multi', 'remote-source': ['PayrollColumn', 'id', 'name'] }],
['status', {
label: 'Status', type: 'select', source: [['Draft', 'Draft'], ['Completed', 'Completed']], sort: 'none',
}],
];
}
postRenderForm(object, $tempDomObj) {
if (object != null && object !== undefined && object.id !== undefined && object.id != null) {
$tempDomObj.find('#pay_period').attr('disabled', 'disabled');
$tempDomObj.find('#department').attr('disabled', 'disabled');
// $tempDomObj.find("#date_start").attr('disabled','disabled');
// $tempDomObj.find("#date_end").attr('disabled','disabled');
// $tempDomObj.find("#column_template").attr('disabled','disabled');
}
}
process(id, status) {
// eslint-disable-next-line no-global-assign
modJs = modJsList.tabPayrollData;
modJs.setCurrentPayroll(id);
$('#Payroll').hide();
$('#PayrollData').show();
$('#PayrollDataButtons').show();
if (status === 'Completed') {
$('.completeBtnTable').hide();
$('.saveBtnTable').hide();
} else {
$('.completeBtnTable').show();
$('.saveBtnTable').show();
}
modJs.get([]);
}
getActionButtonsHtml(id, data) {
const editButton = '<img class="tableActionButton" src="_BASE_images/edit.png" style="cursor:pointer;" rel="tooltip" title="Edit" onclick="modJs.edit(_id_);return false;"></img>';
const processButton = '<img class="tableActionButton" src="_BASE_images/run.png" style="margin-left:15px;cursor:pointer;" rel="tooltip" title="Process" onclick="modJs.process(_id_,\'_status_\');return false;"></img>';
const deleteButton = '<img class="tableActionButton" src="_BASE_images/delete.png" style="margin-left:15px;cursor:pointer;" rel="tooltip" title="Delete" onclick="modJs.deleteRow(_id_);return false;"></img>';
const cloneButton = '<img class="tableActionButton" src="_BASE_images/clone.png" style="margin-left:15px;cursor:pointer;" rel="tooltip" title="Copy" onclick="modJs.copyRow(_id_);return false;"></img>';
let html = '<div style="width:132px;">_edit__process__clone__delete_</div>';
if (this.showAddNew) {
html = html.replace('_clone_', cloneButton);
} else {
html = html.replace('_clone_', '');
}
if (this.showDelete) {
html = html.replace('_delete_', deleteButton);
} else {
html = html.replace('_delete_', '');
}
if (this.showEdit) {
html = html.replace('_edit_', editButton);
} else {
html = html.replace('_edit_', '');
}
html = html.replace('_process_', processButton);
html = html.replace(/_id_/g, id);
html = html.replace(/_status_/g, data[6]);
html = html.replace(/_BASE_/g, this.baseUrl);
return html;
}
get(callBackData) {
$('#PayrollData').hide();
$('#PayrollForm').hide();
$('#PayrollDataButtons').hide();
$('#Payroll').show();
modJsList.tabPayrollData.setCurrentPayroll(null);
super.get(callBackData);
}
getHelpLink() {
return 'https://icehrm.gitbook.io/icehrm/payroll-and-expenses/payroll-management';
}
}
/**
* PayrollDataAdapter
*/
class PayrollDataAdapter extends TableEditAdapter {
constructor(endPoint, tab, filter, orderBy) {
super(endPoint, tab, filter, orderBy);
this.cellDataUpdates = {};
this.payrollId = null;
}
validateCellValue(element, evt, newValue) {
modJs.addCellDataUpdate(element.data('colId'), element.data('rowId'), newValue);
return true;
}
setCurrentPayroll(val) {
this.payrollId = val;
}
addAdditionalRequestData(type, req) {
if (type === 'updateData') {
req.payrollId = this.payrollId;
} else if (type === 'updateAllData') {
req.payrollId = this.payrollId;
} else if (type === 'getAllData') {
req.payrollId = this.payrollId;
}
return req;
}
modifyCSVHeader(header) {
header.unshift('');
return header;
}
getCSVData() {
let csv = '';
for (let i = 0; i < this.csvData.length; i++) {
csv += this.csvData[i].join(',');
if (i < this.csvData.length - 1) {
csv += '\r\n';
}
}
return csv;
}
downloadPayroll() {
const element = document.createElement('a');
element.setAttribute('href', `data:text/plain;charset=utf-8,${encodeURIComponent(this.getCSVData())}`);
element.setAttribute('download', `payroll_${this.payrollId}.csv`);
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
}
getHelpLink() {
return 'https://icehrm.gitbook.io/icehrm/payroll-and-expenses/payroll-management';
}
}
/**
* PayrollColumnAdapter
*/
class PayrollColumnAdapter extends AdapterBase {
constructor(endPoint, tab, filter, orderBy) {
super(endPoint, tab, filter, orderBy);
this.codeMirror = CodeMirror;
}
getDataMapping() {
return [
'id',
'name',
'colorder',
'calculation_hook',
'deduction_group',
'editable',
'enabled',
];
}
getHeaders() {
return [
{ sTitle: 'ID', bVisible: false },
{ sTitle: 'Name' },
{ sTitle: 'Column Order' },
{ sTitle: 'Calculation Method' },
{ sTitle: 'Payroll Group' },
{ sTitle: 'Editable' },
{ sTitle: 'Enabled' },
];
}
getFormFields() {
const fucntionColumnList = ['calculation_columns', {
label: 'Calculation Columns',
type: 'datagroup',
form: [
['name', { label: 'Name', type: 'text', validation: '' }],
['column', { label: 'Column', type: 'select2', 'remote-source': ['PayrollColumn', 'id', 'name'] }],
],
html: '<div id="#_id_#" class="panel panel-default">#_delete_##_edit_#<div class="panel-body">#_renderFunction_#</div></div>',
validation: 'none',
render(item) {
const output = `Variable:${item.name}`;
return output;
},
}];
return [
['id', { label: 'ID', type: 'hidden' }],
['name', { label: 'Name', type: 'text', validation: '' }],
['calculation_hook', {
label: 'Predefined Calculations', type: 'select2', 'allow-null': true, 'null-label': 'None', 'remote-source': ['CalculationHook', 'code', 'name'],
}],
['deduction_group', {
label: 'Payroll Group', type: 'select2', 'allow-null': true, 'null-label': 'Common', 'remote-source': ['DeductionGroup', 'id', 'name'],
}],
['salary_components', { label: 'Salary Components', type: 'select2multi', 'remote-source': ['SalaryComponent', 'id', 'name'] }],
['deductions', { label: 'Calculation Method', type: 'select2multi', 'remote-source': ['Deduction', 'id', 'name'] }],
['add_columns', { label: 'Columns to Add', type: 'select2multi', 'remote-source': ['PayrollColumn', 'id', 'name'] }],
['sub_columns', { label: 'Columns to Subtract', type: 'select2multi', 'remote-source': ['PayrollColumn', 'id', 'name'] }],
['colorder', { label: 'Column Order', type: 'text', validation: 'number' }],
['editable', { label: 'Editable', type: 'select', source: [['Yes', 'Yes'], ['No', 'No']] }],
['enabled', { label: 'Enabled', type: 'select', source: [['Yes', 'Yes'], ['No', 'No']] }],
['default_value', { label: 'Default Value', type: 'text', validation: '' }],
fucntionColumnList,
['function_type', { label: 'Function Type', type: 'select', source: [['Advanced', 'Advanced'], ['Simple', 'Simple']] }],
['calculation_function', { label: 'Function', type: 'code', validation: 'none' }],
];
}
getFilters() {
return [
['deduction_group', {
label: 'Payroll Group', type: 'select2', 'allow-null': false, 'remote-source': ['DeductionGroup', 'id', 'name'],
}],
];
}
getHelpLink() {
return 'https://icehrm.gitbook.io/icehrm/payroll-and-expenses/payroll-management';
}
}
/**
* PayrollColumnTemplateAdapter
*/
class PayrollColumnTemplateAdapter extends AdapterBase {
getDataMapping() {
return [
'id',
'name',
];
}
getHeaders() {
return [
{ sTitle: 'ID', bVisible: true },
{ sTitle: 'Name' },
];
}
getFormFields() {
return [
['id', { label: 'ID', type: 'hidden' }],
['name', { label: 'Name', type: 'text', validation: '' }],
['columns', { label: 'Payroll Columns', type: 'select2multi', 'remote-source': ['PayrollColumn', 'id', 'name'] }],
];
}
}
/*
* PayrollEmployeeAdapter
*/
class PayrollEmployeeAdapter extends AdapterBase {
getDataMapping() {
return [
'id',
'employee',
'pay_frequency',
'deduction_group',
'currency',
];
}
getHeaders() {
return [
{ sTitle: 'ID', bVisible: false },
{ sTitle: 'Employee' },
{ sTitle: 'Pay Frequency' },
{ sTitle: 'Payroll Group' },
{ sTitle: 'Currency' },
];
}
getFormFields() {
return [
['id', { label: 'ID', type: 'hidden' }],
['employee', { label: 'Employee', type: 'select2', 'remote-source': ['Employee', 'id', 'first_name+last_name'] }],
['pay_frequency', { label: 'Pay Frequency', type: 'select2', 'remote-source': ['PayFrequency', 'id', 'name'] }],
['currency', { label: 'Currency', type: 'select2', 'remote-source': ['CurrencyType', 'id', 'code'] }],
['deduction_group', {
label: 'Payroll Group', type: 'select2', 'allow-null': true, 'null-label': 'None', 'remote-source': ['DeductionGroup', 'id', 'name'],
}],
['deduction_exemptions', {
label: 'Calculation Exemptions', type: 'select2multi', 'remote-source': ['Deduction', 'id', 'name'], validation: 'none',
}],
['deduction_allowed', {
label: 'Calculations Assigned', type: 'select2multi', 'remote-source': ['Deduction', 'id', 'name'], validation: 'none',
}],
];
}
getFilters() {
return [
['employee', { label: 'Employee', type: 'select2', 'remote-source': ['Employee', 'id', 'first_name+last_name'] }],
];
}
}
/**
* DeductionAdapter
*/
class DeductionAdapter extends AdapterBase {
getDataMapping() {
return [
'id',
'name',
'deduction_group',
];
}
getHeaders() {
return [
{ sTitle: 'ID', bVisible: false },
{ sTitle: 'Name' },
{ sTitle: 'Payroll Group' },
];
}
getFormFields() {
const rangeAmounts = ['rangeAmounts', {
label: 'Calculation Process',
type: 'datagroup',
form: [
['lowerCondition', { label: 'Lower Limit Condition', type: 'select', source: [['No Lower Limit', 'No Lower Limit'], ['gt', 'Greater than'], ['gte', 'Greater than or Equal']] }],
['lowerLimit', { label: 'Lower Limit', type: 'text', validation: 'float' }],
['upperCondition', { label: 'Upper Limit Condition', type: 'select', source: [['No Upper Limit', 'No Upper Limit'], ['lt', 'Less than'], ['lte', 'Less than or Equal']] }],
['upperLimit', { label: 'Upper Limit', type: 'text', validation: 'float' }],
['amount', { label: 'Value', type: 'text', validation: '' }],
],
html: '<div id="#_id_#" class="panel panel-default">#_delete_##_edit_#<div class="panel-body">#_renderFunction_#</div></div>',
validation: 'none',
'custom-validate-function': function (data) {
const res = {};
res.valid = true;
if (data.lowerCondition === 'No Lower Limit') {
data.lowerLimit = 0;
}
if (data.upperCondition === 'No Upper Limit') {
data.upperLimit = 0;
}
res.params = data;
return res;
},
render(item) {
let output = '';
const getSymbol = function (text) {
const map = {};
map.gt = '>';
map.gte = '>=';
map.lt = '<';
map.lte = '<=';
return map[text];
};
if (item.lowerCondition !== 'No Lower Limit') {
output += `${item.lowerLimit} ${getSymbol(item.lowerCondition)} `;
}
if (item.upperCondition !== 'No Upper Limit') {
output += ' and ';
output += `${getSymbol(item.upperCondition)} ${item.upperLimit} `;
}
if (output === '') {
return `Deduction is ${item.amount} for all ranges`;
}
return `If salary component ${output} deduction is ${item.amount}`;
},
}];
return [
['id', { label: 'ID', type: 'hidden' }],
['name', { label: 'Name', type: 'text', validation: '' }],
['componentType', {
label: 'Salary Component Type', type: 'select2multi', 'allow-null': true, 'remote-source': ['SalaryComponentType', 'id', 'name'],
}],
['component', {
label: 'Salary Component', type: 'select2multi', 'allow-null': true, 'remote-source': ['SalaryComponent', 'id', 'name'],
}],
['payrollColumn', {
label: 'Payroll Report Column', type: 'select2', 'allow-null': true, 'remote-source': ['PayrollColumn', 'id', 'name'],
}],
rangeAmounts,
['deduction_group', {
label: 'Payroll Group', type: 'select2', 'allow-null': false, 'remote-source': ['DeductionGroup', 'id', 'name'],
}],
];
}
}
/*
* DeductionGroupAdapter
*/
class DeductionGroupAdapter extends AdapterBase {
getDataMapping() {
return [
'id',
'name',
'description',
];
}
getHeaders() {
return [
{ sTitle: 'ID', bVisible: false },
{ sTitle: 'Name' },
{ sTitle: 'Details' },
];
}
getFormFields() {
return [
['id', { label: 'ID', type: 'hidden' }],
['name', { label: 'Name', type: 'text', validation: '' }],
['description', { label: 'Details', type: 'textarea', validation: 'none' }],
];
}
getActionButtonsHtml(id) {
let html = '<div style="width:150px;">'
+ '<img class="tableActionButton" src="_BASE_images/edit.png" style="margin-left:15px;cursor:pointer;" rel="tooltip" title="Edit" onclick="modJs.edit(_id_);return false;"></img>'
+ '<img class="tableActionButton" src="_BASE_images/delete.png" style="margin-left:15px;cursor:pointer;" rel="tooltip" title="Delete" onclick="modJs.deletePayrollGroup(_id_);return false;"></img>'
+ '<img class="tableActionButton" src="_BASE_images/clone.png" style="margin-left:15px;cursor:pointer;" rel="tooltip" title="Duplicate" onclick="modJs.copyRow(_id_);return false;"></img>'
+ '</div>';
html = html.replace(/_id_/g, id);
html = html.replace(/_BASE_/g, this.baseUrl);
return html;
}
deletePayrollGroup(id) {
if (confirm('Are you sure you want to delete this payroll group? Deleting the payroll group will delete all the Payroll columns and Saved calculations attached to this Payroll Group')) {
// Terminate
} else {
return;
}
const params = {};
params.id = id;
const reqJson = JSON.stringify(params);
const callBackData = [];
callBackData.callBackData = [];
callBackData.callBackSuccess = 'deletePayrollGroupSuccessCallback';
callBackData.callBackFail = 'deletePayrollGroupFailCallback';
this.customAction('deletePayrollGroup', 'admin=payroll', reqJson, callBackData);
}
deletePayrollGroupSuccessCallback(callBackData) {
this.showMessage('Success', 'Payroll Group Deleted ');
this.get([]);
}
deletePayrollGroupFailCallback(callBackData) {
this.showMessage('Error occured while deleting Payroll Group', callBackData);
}
}
/*
* PayslipTemplateAdapter
*/
class PayslipTemplateAdapter extends AdapterBase {
getDataMapping() {
return [
'id',
'name',
];
}
getHeaders() {
return [
{ sTitle: 'ID', bVisible: false },
{ sTitle: 'Name' },
];
}
getFormFields() {
const payslipFields = ['data', {
label: 'Payslip Fields',
type: 'datagroup',
form: [
['type', {
label: 'Type', type: 'select', sort: 'none', source: [['Payroll Column', 'Payroll Column'], ['Text', 'Text'], ['Company Name', 'Company Name'], ['Company Logo', 'Company Logo'], ['Separators', 'Separators']],
}],
['payrollColumn', {
label: 'Payroll Column', type: 'select2', sort: 'none', 'allow-null': true, 'null-label': 'None', 'remote-source': ['PayrollColumn', 'id', 'name'],
}],
['label', { label: 'Label', type: 'text', validation: 'none' }],
['text', { label: 'Text', type: 'textarea', validation: 'none' }],
['status', {
label: 'Status', type: 'select', sort: 'none', source: [['Show', 'Show'], ['Hide', 'Hide']],
}],
],
// "html":'<div id="#_id_#" class="panel panel-default">#_delete_##_edit_#<div class="panel-body"><table class="table table-striped"><tr><td>Type</td><td>#_type_#</td></tr><tr><td>Label</td><td>#_label_#</td></tr><tr><td>Text</td><td>#_text_#</td></tr><tr><td>Font Size</td><td>#_fontSize_#</td></tr><tr><td>Font Style</td><td>#_fontStyle_#</td></tr><tr><td>Font Color</td><td>#_fontColor_#</td></tr><tr><td>Status</td><td>#_status_#</td></tr></table> </div></div>',
html: '<div id="#_id_#" class="panel panel-default">#_delete_##_edit_#<div class="panel-body">#_type_# #_label_# <br/> #_text_#</div></div>',
validation: 'none',
'custom-validate-function': function (data) {
const res = {};
res.valid = true;
if (data.type === 'Payroll Column') {
if (data.payrollColumn === 'NULL') {
res.valid = false;
res.message = 'Please select payroll column';
}
} else {
data.payrollColumn = 'NULL';
}
if (data.type === 'Text') {
if (data.text === '') {
res.valid = false;
res.message = 'Text can not be empty';
}
}
res.params = data;
return res;
},
}];
return [
['id', { label: 'ID', type: 'hidden' }],
['name', { label: 'Name', type: 'text', validation: '' }],
payslipFields,
];
}
}
module.exports = {
PaydayAdapter,
PayrollAdapter,
PayrollDataAdapter,
PayrollColumnAdapter,
PayrollColumnTemplateAdapter,
PayrollEmployeeAdapter,
DeductionAdapter,
DeductionGroupAdapter,
PayslipTemplateAdapter,
};