mirror of
https://github.com/frappe/erpnext.git
synced 2026-09-17 10:36:31 +00:00
fix: wrong payment days in salary slip for employees joining/leaving during mid payroll dates (backport #29082) (#30099)
Co-authored-by: Rucha Mahabal <ruchamahabal2@gmail.com> Co-authored-by: Dany Robert <danyrt@wahni.com>
This commit is contained in:
@@ -174,16 +174,22 @@ def get_month_map():
|
||||
def get_unmarked_days(employee, month, exclude_holidays=0):
|
||||
import calendar
|
||||
month_map = get_month_map()
|
||||
|
||||
today = get_datetime()
|
||||
|
||||
dates_of_month = ['{}-{}-{}'.format(today.year, month_map[month], r) for r in range(1, calendar.monthrange(today.year, month_map[month])[1] + 1)]
|
||||
joining_date, relieving_date = frappe.get_cached_value("Employee", employee, ["date_of_joining", "relieving_date"])
|
||||
start_day = 1
|
||||
end_day = calendar.monthrange(today.year, month_map[month])[1] + 1
|
||||
|
||||
length = len(dates_of_month)
|
||||
month_start, month_end = dates_of_month[0], dates_of_month[length-1]
|
||||
if joining_date and joining_date.month == month_map[month]:
|
||||
start_day = joining_date.day
|
||||
|
||||
if relieving_date and relieving_date.month == month_map[month]:
|
||||
end_day = relieving_date.day + 1
|
||||
|
||||
records = frappe.get_all("Attendance", fields = ['attendance_date', 'employee'] , filters = [
|
||||
dates_of_month = ['{}-{}-{}'.format(today.year, month_map[month], r) for r in range(start_day, end_day)]
|
||||
month_start, month_end = dates_of_month[0], dates_of_month[-1]
|
||||
|
||||
records = frappe.get_all("Attendance", fields=['attendance_date', 'employee'], filters=[
|
||||
["attendance_date", ">=", month_start],
|
||||
["attendance_date", "<=", month_end],
|
||||
["employee", "=", employee],
|
||||
@@ -200,7 +206,7 @@ def get_unmarked_days(employee, month, exclude_holidays=0):
|
||||
|
||||
for date in dates_of_month:
|
||||
date_time = get_datetime(date)
|
||||
if today.day == date_time.day and today.month == date_time.month:
|
||||
if today.day <= date_time.day and today.month <= date_time.month:
|
||||
break
|
||||
if date_time not in marked_days:
|
||||
unmarked_days.append(date)
|
||||
|
||||
@@ -4,17 +4,104 @@
|
||||
import unittest
|
||||
|
||||
import frappe
|
||||
from frappe.utils import nowdate
|
||||
from frappe.utils import add_days, get_first_day, getdate, nowdate
|
||||
|
||||
from erpnext.hr.doctype.attendance.attendance import (
|
||||
get_month_map,
|
||||
get_unmarked_days,
|
||||
mark_attendance,
|
||||
)
|
||||
from erpnext.hr.doctype.employee.test_employee import make_employee
|
||||
from erpnext.hr.doctype.leave_application.test_leave_application import get_first_sunday
|
||||
|
||||
test_records = frappe.get_test_records('Attendance')
|
||||
|
||||
class TestAttendance(unittest.TestCase):
|
||||
def test_mark_absent(self):
|
||||
from erpnext.hr.doctype.employee.test_employee import make_employee
|
||||
employee = make_employee("test_mark_absent@example.com")
|
||||
date = nowdate()
|
||||
frappe.db.delete('Attendance', {'employee':employee, 'attendance_date':date})
|
||||
from erpnext.hr.doctype.attendance.attendance import mark_attendance
|
||||
attendance = mark_attendance(employee, date, 'Absent')
|
||||
fetch_attendance = frappe.get_value('Attendance', {'employee':employee, 'attendance_date':date, 'status':'Absent'})
|
||||
self.assertEqual(attendance, fetch_attendance)
|
||||
|
||||
def test_unmarked_days(self):
|
||||
first_day = get_first_day(getdate())
|
||||
|
||||
employee = make_employee('test_unmarked_days@example.com', date_of_joining=add_days(first_day, -1))
|
||||
frappe.db.delete('Attendance', {'employee': employee})
|
||||
|
||||
from erpnext.payroll.doctype.salary_slip.test_salary_slip import make_holiday_list
|
||||
holiday_list = make_holiday_list()
|
||||
frappe.db.set_value('Employee', employee, 'holiday_list', holiday_list)
|
||||
|
||||
first_sunday = get_first_sunday(holiday_list)
|
||||
mark_attendance(employee, first_day, 'Present')
|
||||
month_name = get_month_name(first_day)
|
||||
|
||||
unmarked_days = get_unmarked_days(employee, month_name)
|
||||
unmarked_days = [getdate(date) for date in unmarked_days]
|
||||
|
||||
# attendance already marked for the day
|
||||
self.assertNotIn(first_day, unmarked_days)
|
||||
# attendance unmarked
|
||||
self.assertIn(getdate(add_days(first_day, 1)), unmarked_days)
|
||||
# holiday considered in unmarked days
|
||||
self.assertIn(first_sunday, unmarked_days)
|
||||
|
||||
def test_unmarked_days_excluding_holidays(self):
|
||||
first_day = get_first_day(getdate())
|
||||
|
||||
employee = make_employee('test_unmarked_days@example.com', date_of_joining=add_days(first_day, -1))
|
||||
frappe.db.delete('Attendance', {'employee': employee})
|
||||
|
||||
from erpnext.payroll.doctype.salary_slip.test_salary_slip import make_holiday_list
|
||||
holiday_list = make_holiday_list()
|
||||
frappe.db.set_value('Employee', employee, 'holiday_list', holiday_list)
|
||||
|
||||
first_sunday = get_first_sunday(holiday_list)
|
||||
mark_attendance(employee, first_day, 'Present')
|
||||
month_name = get_month_name(first_day)
|
||||
|
||||
unmarked_days = get_unmarked_days(employee, month_name, exclude_holidays=True)
|
||||
unmarked_days = [getdate(date) for date in unmarked_days]
|
||||
|
||||
# attendance already marked for the day
|
||||
self.assertNotIn(first_day, unmarked_days)
|
||||
# attendance unmarked
|
||||
self.assertIn(getdate(add_days(first_day, 1)), unmarked_days)
|
||||
# holidays not considered in unmarked days
|
||||
self.assertNotIn(first_sunday, unmarked_days)
|
||||
|
||||
def test_unmarked_days_as_per_joining_and_relieving_dates(self):
|
||||
first_day = get_first_day(getdate())
|
||||
|
||||
doj = add_days(first_day, 1)
|
||||
relieving_date = add_days(first_day, 5)
|
||||
employee = make_employee('test_unmarked_days_as_per_doj@example.com', date_of_joining=doj,
|
||||
date_of_relieving=relieving_date)
|
||||
frappe.db.delete('Attendance', {'employee': employee})
|
||||
|
||||
attendance_date = add_days(first_day, 2)
|
||||
mark_attendance(employee, attendance_date, 'Present')
|
||||
month_name = get_month_name(first_day)
|
||||
|
||||
unmarked_days = get_unmarked_days(employee, month_name)
|
||||
unmarked_days = [getdate(date) for date in unmarked_days]
|
||||
|
||||
# attendance already marked for the day
|
||||
self.assertNotIn(attendance_date, unmarked_days)
|
||||
# date before doj not in unmarked days
|
||||
self.assertNotIn(add_days(doj, -1), unmarked_days)
|
||||
# date after relieving not in unmarked days
|
||||
self.assertNotIn(add_days(relieving_date, 1), unmarked_days)
|
||||
|
||||
def tearDown(self):
|
||||
frappe.db.rollback()
|
||||
|
||||
|
||||
def get_month_name(date):
|
||||
month_number = date.month
|
||||
for month, number in get_month_map().items():
|
||||
if number == month_number:
|
||||
return month
|
||||
Reference in New Issue
Block a user