Merge pull request #24169 from Anurag810/payroll-entry-fixes
fix: allow addition and removal of employee in payroll Entry
This commit is contained in:
commit
bb0fd33ac5
@ -17,8 +17,7 @@
|
|||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Employee",
|
"label": "Employee",
|
||||||
"options": "Employee",
|
"options": "Employee"
|
||||||
"read_only": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fetch_from": "employee.employee_name",
|
"fetch_from": "employee.employee_name",
|
||||||
@ -52,7 +51,7 @@
|
|||||||
],
|
],
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-09-30 12:40:07.999878",
|
"modified": "2020-12-17 15:43:29.542977",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Payroll",
|
"module": "Payroll",
|
||||||
"name": "Payroll Employee Detail",
|
"name": "Payroll Employee Detail",
|
||||||
|
@ -10,15 +10,22 @@ frappe.ui.form.on('Payroll Entry', {
|
|||||||
}
|
}
|
||||||
frm.toggle_reqd(['payroll_frequency'], !frm.doc.salary_slip_based_on_timesheet);
|
frm.toggle_reqd(['payroll_frequency'], !frm.doc.salary_slip_based_on_timesheet);
|
||||||
|
|
||||||
frm.set_query("department", function() {
|
frm.events.department_filters(frm);
|
||||||
|
frm.events.payroll_payable_account_filters(frm);
|
||||||
|
},
|
||||||
|
|
||||||
|
department_filters: function (frm) {
|
||||||
|
frm.set_query("department", function () {
|
||||||
return {
|
return {
|
||||||
"filters": {
|
"filters": {
|
||||||
"company": frm.doc.company,
|
"company": frm.doc.company,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
|
||||||
frm.set_query("payroll_payable_account", function() {
|
payroll_payable_account_filters: function (frm) {
|
||||||
|
frm.set_query("payroll_payable_account", function () {
|
||||||
return {
|
return {
|
||||||
filters: {
|
filters: {
|
||||||
"company": frm.doc.company,
|
"company": frm.doc.company,
|
||||||
@ -29,12 +36,12 @@ frappe.ui.form.on('Payroll Entry', {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
refresh: function(frm) {
|
refresh: function (frm) {
|
||||||
if (frm.doc.docstatus == 0) {
|
if (frm.doc.docstatus == 0) {
|
||||||
if(!frm.is_new()) {
|
if (!frm.is_new()) {
|
||||||
frm.page.clear_primary_action();
|
frm.page.clear_primary_action();
|
||||||
frm.add_custom_button(__("Get Employees"),
|
frm.add_custom_button(__("Get Employees"),
|
||||||
function() {
|
function () {
|
||||||
frm.events.get_employee_details(frm);
|
frm.events.get_employee_details(frm);
|
||||||
}
|
}
|
||||||
).toggleClass('btn-primary', !(frm.doc.employees || []).length);
|
).toggleClass('btn-primary', !(frm.doc.employees || []).length);
|
||||||
@ -42,7 +49,7 @@ frappe.ui.form.on('Payroll Entry', {
|
|||||||
if ((frm.doc.employees || []).length) {
|
if ((frm.doc.employees || []).length) {
|
||||||
frm.page.clear_primary_action();
|
frm.page.clear_primary_action();
|
||||||
frm.page.set_primary_action(__('Create Salary Slips'), () => {
|
frm.page.set_primary_action(__('Create Salary Slips'), () => {
|
||||||
frm.save('Submit').then(()=>{
|
frm.save('Submit').then(() => {
|
||||||
frm.page.clear_primary_action();
|
frm.page.clear_primary_action();
|
||||||
frm.refresh();
|
frm.refresh();
|
||||||
frm.events.refresh(frm);
|
frm.events.refresh(frm);
|
||||||
@ -61,48 +68,48 @@ frappe.ui.form.on('Payroll Entry', {
|
|||||||
doc: frm.doc,
|
doc: frm.doc,
|
||||||
method: 'fill_employee_details',
|
method: 'fill_employee_details',
|
||||||
}).then(r => {
|
}).then(r => {
|
||||||
if (r.docs && r.docs[0].employees){
|
if (r.docs && r.docs[0].employees) {
|
||||||
frm.employees = r.docs[0].employees;
|
frm.employees = r.docs[0].employees;
|
||||||
frm.dirty();
|
frm.dirty();
|
||||||
frm.save();
|
frm.save();
|
||||||
frm.refresh();
|
frm.refresh();
|
||||||
if(r.docs[0].validate_attendance){
|
if (r.docs[0].validate_attendance) {
|
||||||
render_employee_attendance(frm, r.message);
|
render_employee_attendance(frm, r.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
create_salary_slips: function(frm) {
|
create_salary_slips: function (frm) {
|
||||||
frm.call({
|
frm.call({
|
||||||
doc: frm.doc,
|
doc: frm.doc,
|
||||||
method: "create_salary_slips",
|
method: "create_salary_slips",
|
||||||
callback: function(r) {
|
callback: function () {
|
||||||
frm.refresh();
|
frm.refresh();
|
||||||
frm.toolbar.refresh();
|
frm.toolbar.refresh();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
add_context_buttons: function(frm) {
|
add_context_buttons: function (frm) {
|
||||||
if(frm.doc.salary_slips_submitted || (frm.doc.__onload && frm.doc.__onload.submitted_ss)) {
|
if (frm.doc.salary_slips_submitted || (frm.doc.__onload && frm.doc.__onload.submitted_ss)) {
|
||||||
frm.events.add_bank_entry_button(frm);
|
frm.events.add_bank_entry_button(frm);
|
||||||
} else if(frm.doc.salary_slips_created) {
|
} else if (frm.doc.salary_slips_created) {
|
||||||
frm.add_custom_button(__("Submit Salary Slip"), function() {
|
frm.add_custom_button(__("Submit Salary Slip"), function () {
|
||||||
submit_salary_slip(frm);
|
submit_salary_slip(frm);
|
||||||
}).addClass("btn-primary");
|
}).addClass("btn-primary");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
add_bank_entry_button: function(frm) {
|
add_bank_entry_button: function (frm) {
|
||||||
frappe.call({
|
frappe.call({
|
||||||
method: 'erpnext.payroll.doctype.payroll_entry.payroll_entry.payroll_entry_has_bank_entries',
|
method: 'erpnext.payroll.doctype.payroll_entry.payroll_entry.payroll_entry_has_bank_entries',
|
||||||
args: {
|
args: {
|
||||||
'name': frm.doc.name
|
'name': frm.doc.name
|
||||||
},
|
},
|
||||||
callback: function(r) {
|
callback: function (r) {
|
||||||
if (r.message && !r.message.submitted) {
|
if (r.message && !r.message.submitted) {
|
||||||
frm.add_custom_button("Make Bank Entry", function() {
|
frm.add_custom_button("Make Bank Entry", function () {
|
||||||
make_bank_entry(frm);
|
make_bank_entry(frm);
|
||||||
}).addClass("btn-primary");
|
}).addClass("btn-primary");
|
||||||
}
|
}
|
||||||
@ -141,8 +148,37 @@ frappe.ui.form.on('Payroll Entry', {
|
|||||||
},
|
},
|
||||||
|
|
||||||
payroll_frequency: function (frm) {
|
payroll_frequency: function (frm) {
|
||||||
frm.trigger("set_start_end_dates");
|
frm.trigger("set_start_end_dates").then( ()=> {
|
||||||
frm.events.clear_employee_table(frm);
|
frm.events.clear_employee_table(frm);
|
||||||
|
frm.events.get_employee_with_salary_slip_and_set_query(frm);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
employee_filters: function (frm, emp_list) {
|
||||||
|
frm.set_query('employee', 'employees', () => {
|
||||||
|
return {
|
||||||
|
filters: {
|
||||||
|
name: ["not in", emp_list]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
get_employee_with_salary_slip_and_set_query: function (frm) {
|
||||||
|
frappe.db.get_list('Salary Slip', {
|
||||||
|
filters: {
|
||||||
|
start_date: frm.doc.start_date,
|
||||||
|
end_date: frm.doc.end_date,
|
||||||
|
docstatus: 1,
|
||||||
|
},
|
||||||
|
fields: ['employee']
|
||||||
|
}).then((emp) => {
|
||||||
|
var emp_list = [];
|
||||||
|
emp.forEach((employee_data) => {
|
||||||
|
emp_list.push(Object.values(employee_data)[0]);
|
||||||
|
});
|
||||||
|
frm.events.employee_filters(frm, emp_list);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
company: function (frm) {
|
company: function (frm) {
|
||||||
@ -164,17 +200,17 @@ frappe.ui.form.on('Payroll Entry', {
|
|||||||
from_currency: frm.doc.currency,
|
from_currency: frm.doc.currency,
|
||||||
to_currency: company_currency,
|
to_currency: company_currency,
|
||||||
},
|
},
|
||||||
callback: function(r) {
|
callback: function (r) {
|
||||||
frm.set_value("exchange_rate", flt(r.message));
|
frm.set_value("exchange_rate", flt(r.message));
|
||||||
frm.set_df_property('exchange_rate', 'hidden', 0);
|
frm.set_df_property('exchange_rate', 'hidden', 0);
|
||||||
frm.set_df_property("exchange_rate", "description", "1 " + frm.doc.currency
|
frm.set_df_property("exchange_rate", "description", "1 " + frm.doc.currency +
|
||||||
+ " = [?] " + company_currency);
|
" = [?] " + company_currency);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
frm.set_value("exchange_rate", 1.0);
|
frm.set_value("exchange_rate", 1.0);
|
||||||
frm.set_df_property('exchange_rate', 'hidden', 1);
|
frm.set_df_property('exchange_rate', 'hidden', 1);
|
||||||
frm.set_df_property("exchange_rate", "description", "" );
|
frm.set_df_property("exchange_rate", "description", "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -192,9 +228,9 @@ frappe.ui.form.on('Payroll Entry', {
|
|||||||
},
|
},
|
||||||
|
|
||||||
start_date: function (frm) {
|
start_date: function (frm) {
|
||||||
if(!in_progress && frm.doc.start_date){
|
if (!in_progress && frm.doc.start_date) {
|
||||||
frm.trigger("set_end_date");
|
frm.trigger("set_end_date");
|
||||||
}else{
|
} else {
|
||||||
// reset flag
|
// reset flag
|
||||||
in_progress = false;
|
in_progress = false;
|
||||||
}
|
}
|
||||||
@ -228,7 +264,7 @@ frappe.ui.form.on('Payroll Entry', {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
set_end_date: function(frm){
|
set_end_date: function (frm) {
|
||||||
frappe.call({
|
frappe.call({
|
||||||
method: 'erpnext.payroll.doctype.payroll_entry.payroll_entry.get_end_date',
|
method: 'erpnext.payroll.doctype.payroll_entry.payroll_entry.get_end_date',
|
||||||
args: {
|
args: {
|
||||||
@ -243,19 +279,19 @@ frappe.ui.form.on('Payroll Entry', {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
validate_attendance: function(frm){
|
validate_attendance: function (frm) {
|
||||||
if(frm.doc.validate_attendance && frm.doc.employees){
|
if (frm.doc.validate_attendance && frm.doc.employees) {
|
||||||
frappe.call({
|
frappe.call({
|
||||||
method: 'validate_employee_attendance',
|
method: 'validate_employee_attendance',
|
||||||
args: {},
|
args: {},
|
||||||
callback: function(r) {
|
callback: function (r) {
|
||||||
render_employee_attendance(frm, r.message);
|
render_employee_attendance(frm, r.message);
|
||||||
},
|
},
|
||||||
doc: frm.doc,
|
doc: frm.doc,
|
||||||
freeze: true,
|
freeze: true,
|
||||||
freeze_message: __('Validating Employee Attendance...')
|
freeze_message: __('Validating Employee Attendance...')
|
||||||
});
|
});
|
||||||
}else{
|
} else {
|
||||||
frm.fields_dict.attendance_detail_html.html("");
|
frm.fields_dict.attendance_detail_html.html("");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -270,18 +306,20 @@ frappe.ui.form.on('Payroll Entry', {
|
|||||||
|
|
||||||
const submit_salary_slip = function (frm) {
|
const submit_salary_slip = function (frm) {
|
||||||
frappe.confirm(__('This will submit Salary Slips and create accrual Journal Entry. Do you want to proceed?'),
|
frappe.confirm(__('This will submit Salary Slips and create accrual Journal Entry. Do you want to proceed?'),
|
||||||
function() {
|
function () {
|
||||||
frappe.call({
|
frappe.call({
|
||||||
method: 'submit_salary_slips',
|
method: 'submit_salary_slips',
|
||||||
args: {},
|
args: {},
|
||||||
callback: function() {frm.events.refresh(frm);},
|
callback: function () {
|
||||||
|
frm.events.refresh(frm);
|
||||||
|
},
|
||||||
doc: frm.doc,
|
doc: frm.doc,
|
||||||
freeze: true,
|
freeze: true,
|
||||||
freeze_message: __('Submitting Salary Slips and creating Journal Entry...')
|
freeze_message: __('Submitting Salary Slips and creating Journal Entry...')
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
function() {
|
function () {
|
||||||
if(frappe.dom.freeze_count) {
|
if (frappe.dom.freeze_count) {
|
||||||
frappe.dom.unfreeze();
|
frappe.dom.unfreeze();
|
||||||
frm.events.refresh(frm);
|
frm.events.refresh(frm);
|
||||||
}
|
}
|
||||||
@ -295,9 +333,11 @@ let make_bank_entry = function (frm) {
|
|||||||
return frappe.call({
|
return frappe.call({
|
||||||
doc: cur_frm.doc,
|
doc: cur_frm.doc,
|
||||||
method: "make_payment_entry",
|
method: "make_payment_entry",
|
||||||
callback: function() {
|
callback: function () {
|
||||||
frappe.set_route(
|
frappe.set_route(
|
||||||
'List', 'Journal Entry', {"Journal Entry Account.reference_name": frm.doc.name}
|
'List', 'Journal Entry', {
|
||||||
|
"Journal Entry Account.reference_name": frm.doc.name
|
||||||
|
}
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
freeze: true,
|
freeze: true,
|
||||||
@ -309,11 +349,19 @@ let make_bank_entry = function (frm) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let render_employee_attendance = function (frm, data) {
|
||||||
let render_employee_attendance = function(frm, data) {
|
|
||||||
frm.fields_dict.attendance_detail_html.html(
|
frm.fields_dict.attendance_detail_html.html(
|
||||||
frappe.render_template('employees_to_mark_attendance', {
|
frappe.render_template('employees_to_mark_attendance', {
|
||||||
data: data
|
data: data
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
|
frappe.ui.form.on('Payroll Employee Detail', {
|
||||||
|
employee: function(frm) {
|
||||||
|
frm.events.clear_employee_table(frm);
|
||||||
|
if (!frm.doc.payroll_frequency) {
|
||||||
|
frappe.throw(__("Please set a Payroll Frequency"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
@ -129,8 +129,7 @@
|
|||||||
"fieldname": "employees",
|
"fieldname": "employees",
|
||||||
"fieldtype": "Table",
|
"fieldtype": "Table",
|
||||||
"label": "Employee Details",
|
"label": "Employee Details",
|
||||||
"options": "Payroll Employee Detail",
|
"options": "Payroll Employee Detail"
|
||||||
"read_only": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "section_break_13",
|
"fieldname": "section_break_13",
|
||||||
@ -290,7 +289,7 @@
|
|||||||
"icon": "fa fa-cog",
|
"icon": "fa fa-cog",
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-10-23 13:00:33.753228",
|
"modified": "2020-12-17 15:13:17.766210",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Payroll",
|
"module": "Payroll",
|
||||||
"name": "Payroll Entry",
|
"name": "Payroll Entry",
|
||||||
|
@ -6,7 +6,7 @@ from __future__ import unicode_literals
|
|||||||
import frappe, erpnext
|
import frappe, erpnext
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from dateutil.relativedelta import relativedelta
|
from dateutil.relativedelta import relativedelta
|
||||||
from frappe.utils import cint, flt, nowdate, add_days, getdate, fmt_money, add_to_date, DATE_FORMAT, date_diff
|
from frappe.utils import cint, flt, add_days, getdate, add_to_date, DATE_FORMAT, date_diff, comma_and
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from erpnext.accounts.utils import get_fiscal_year
|
from erpnext.accounts.utils import get_fiscal_year
|
||||||
from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
|
from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
|
||||||
@ -19,16 +19,26 @@ class PayrollEntry(Document):
|
|||||||
# check if salary slips were manually submitted
|
# check if salary slips were manually submitted
|
||||||
entries = frappe.db.count("Salary Slip", {'payroll_entry': self.name, 'docstatus': 1}, ['name'])
|
entries = frappe.db.count("Salary Slip", {'payroll_entry': self.name, 'docstatus': 1}, ['name'])
|
||||||
if cint(entries) == len(self.employees):
|
if cint(entries) == len(self.employees):
|
||||||
self.set_onload("submitted_ss", True)
|
self.set_onload("submitted_ss", True)
|
||||||
|
|
||||||
def on_submit(self):
|
def on_submit(self):
|
||||||
self.create_salary_slips()
|
self.create_salary_slips()
|
||||||
|
|
||||||
def before_submit(self):
|
def before_submit(self):
|
||||||
|
self.validate_employee_details()
|
||||||
if self.validate_attendance:
|
if self.validate_attendance:
|
||||||
if self.validate_employee_attendance():
|
if self.validate_employee_attendance():
|
||||||
frappe.throw(_("Cannot Submit, Employees left to mark attendance"))
|
frappe.throw(_("Cannot Submit, Employees left to mark attendance"))
|
||||||
|
|
||||||
|
def validate_employee_details(self):
|
||||||
|
emp_with_sal_slip = []
|
||||||
|
for employee_details in self.employees:
|
||||||
|
if frappe.db.exists("Salary Slip", {"employee": employee_details.employee, "start_date": self.start_date, "end_date": self.end_date, "docstatus": 1}):
|
||||||
|
emp_with_sal_slip.append(employee_details.employee)
|
||||||
|
|
||||||
|
if len(emp_with_sal_slip):
|
||||||
|
frappe.throw(_("Salary Slip already exists for {0} ").format(comma_and(emp_with_sal_slip)))
|
||||||
|
|
||||||
def on_cancel(self):
|
def on_cancel(self):
|
||||||
frappe.delete_doc("Salary Slip", frappe.db.sql_list("""select name from `tabSalary Slip`
|
frappe.delete_doc("Salary Slip", frappe.db.sql_list("""select name from `tabSalary Slip`
|
||||||
where payroll_entry=%s """, (self.name)))
|
where payroll_entry=%s """, (self.name)))
|
||||||
@ -71,8 +81,17 @@ class PayrollEntry(Document):
|
|||||||
and t2.docstatus = 1
|
and t2.docstatus = 1
|
||||||
%s order by t2.from_date desc
|
%s order by t2.from_date desc
|
||||||
""" % cond, {"sal_struct": tuple(sal_struct), "from_date": self.end_date, "payroll_payable_account": self.payroll_payable_account}, as_dict=True)
|
""" % cond, {"sal_struct": tuple(sal_struct), "from_date": self.end_date, "payroll_payable_account": self.payroll_payable_account}, as_dict=True)
|
||||||
|
|
||||||
|
emp_list = self.remove_payrolled_employees(emp_list)
|
||||||
return emp_list
|
return emp_list
|
||||||
|
|
||||||
|
def remove_payrolled_employees(self, emp_list):
|
||||||
|
for employee_details in emp_list:
|
||||||
|
if frappe.db.exists("Salary Slip", {"employee": employee_details.employee, "start_date": self.start_date, "end_date": self.end_date, "docstatus": 1}):
|
||||||
|
emp_list.remove(employee_details)
|
||||||
|
|
||||||
|
return emp_list
|
||||||
|
|
||||||
def fill_employee_details(self):
|
def fill_employee_details(self):
|
||||||
self.set('employees', [])
|
self.set('employees', [])
|
||||||
employees = self.get_emp_list()
|
employees = self.get_emp_list()
|
||||||
@ -542,7 +561,7 @@ def create_salary_slips_for_employees(employees, args, publish_progress=True):
|
|||||||
title = _("Creating Salary Slips..."))
|
title = _("Creating Salary Slips..."))
|
||||||
else:
|
else:
|
||||||
salary_slip_name = frappe.db.sql(
|
salary_slip_name = frappe.db.sql(
|
||||||
'''SELECT
|
'''SELECT
|
||||||
name
|
name
|
||||||
FROM `tabSalary Slip`
|
FROM `tabSalary Slip`
|
||||||
WHERE company=%s
|
WHERE company=%s
|
||||||
|
Loading…
x
Reference in New Issue
Block a user