-
Notifications
You must be signed in to change notification settings - Fork 821
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2668 from frappe/version-15-hotfix
chore: release v15
- Loading branch information
Showing
17 changed files
with
938 additions
and
252 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,8 @@ | |
from erpnext.setup.doctype.employee.test_employee import make_employee | ||
from erpnext.setup.doctype.holiday_list.test_holiday_list import set_holiday_list | ||
|
||
from hrms.hr.doctype.leave_allocation.leave_allocation import get_unused_leaves | ||
from hrms.hr.doctype.leave_ledger_entry.leave_ledger_entry import process_expired_allocation | ||
from hrms.hr.doctype.leave_period.test_leave_period import create_leave_period | ||
from hrms.hr.doctype.leave_policy.test_leave_policy import create_leave_policy | ||
from hrms.hr.doctype.leave_policy_assignment.leave_policy_assignment import ( | ||
|
@@ -259,3 +261,107 @@ def test_creation_of_leave_ledger_entry_on_submit(self): | |
frappe.db.delete("Additional Salary", {"ref_docname": leave_encashment.name}) | ||
leave_encashment.cancel() | ||
self.assertFalse(frappe.db.exists("Leave Ledger Entry", {"transaction_name": leave_encashment.name})) | ||
|
||
@set_holiday_list("_Test Leave Encashment", "_Test Company") | ||
def test_unused_leaves_after_leave_encashment_for_carry_forwarding_leave_type(self): | ||
employee = make_employee("[email protected]", company="_Test Company") | ||
# allocated 10 leaves, encashed 5 | ||
leave_encashment = self.get_encashment_created_after_leave_period( | ||
employee, is_carry_forward=1, encashment_days=5 | ||
) | ||
# check if unused leaves are 5 before processing expired allocation runs | ||
unused_leaves = get_unused_leaves( | ||
employee, self.leave_type, self.leave_period.from_date, self.leave_period.to_date | ||
) | ||
self.assertEqual(unused_leaves, 5) | ||
|
||
# check if a single leave ledger entry is created | ||
self.assertEqual(frappe.get_value("Leave Type", self.leave_type, "is_carry_forward"), 1) | ||
leave_ledger_entry = frappe.get_all( | ||
"Leave Ledger Entry", fields=["leaves"], filters={"transaction_name": leave_encashment.name} | ||
) | ||
self.assertEqual(len(leave_ledger_entry), 1) | ||
self.assertEqual(leave_ledger_entry[0].leaves, leave_encashment.encashment_days * -1) | ||
|
||
# check if unused leaves are 5 after processing expired allocation runs | ||
process_expired_allocation() | ||
unused_leaves = get_unused_leaves( | ||
employee, self.leave_type, self.leave_period.from_date, self.leave_period.to_date | ||
) | ||
self.assertEqual(unused_leaves, 5) | ||
|
||
@set_holiday_list("_Test Leave Encashment", "_Test Company") | ||
def test_leave_expiry_after_leave_encashment_for_non_carry_forwarding_leave_type(self): | ||
employee = make_employee("[email protected]", company="_Test Company") | ||
# allocated 10 leaves, encashed 3 | ||
|
||
leave_encashment = self.get_encashment_created_after_leave_period( | ||
employee, is_carry_forward=0, encashment_days=3 | ||
) | ||
# when leave encashment is created after leave allocation period is over, | ||
# it's assumed that process expired allocation has expired the leaves, | ||
# hence a reverse ledger entry should be created for the encashment | ||
# check if two leave ledger entries are created | ||
self.assertEqual(frappe.get_value("Leave Type", self.leave_type, "is_carry_forward"), 0) | ||
leave_ledger_entry = frappe.get_all( | ||
"Leave Ledger Entry", | ||
fields="*", | ||
filters={"transaction_name": leave_encashment.name}, | ||
order_by="leaves", | ||
) | ||
self.assertEqual(len(leave_ledger_entry), 2) | ||
self.assertEqual(leave_ledger_entry[0].leaves, leave_encashment.encashment_days * -1) | ||
self.assertEqual(leave_ledger_entry[1].leaves, leave_encashment.encashment_days * 1) | ||
|
||
# check if 10 leaves are expired after processing expired allocation runs | ||
process_expired_allocation() | ||
|
||
expired_leaves = frappe.get_value( | ||
"Leave Ledger Entry", | ||
{"employee": employee, "leave_type": self.leave_type, "is_expired": 1}, | ||
"leaves", | ||
) | ||
self.assertEqual(expired_leaves, -10) | ||
|
||
def get_encashment_created_after_leave_period(self, employee, is_carry_forward, encashment_days): | ||
frappe.db.delete("Leave Period", {"name": self.leave_period.name}) | ||
# create new leave period that has end date of yesterday | ||
start_date = add_days(getdate(), -30) | ||
end_date = add_days(getdate(), -1) | ||
self.leave_period = create_leave_period(start_date, end_date, "_Test Company") | ||
frappe.db.set_value( | ||
"Leave Type", | ||
self.leave_type, | ||
{ | ||
"is_carry_forward": is_carry_forward, | ||
}, | ||
) | ||
|
||
leave_policy = frappe.get_value("Leave Policy", {"title": "Test Leave Policy"}, "name") | ||
data = { | ||
"assignment_based_on": "Leave Period", | ||
"leave_policy": leave_policy, | ||
"leave_period": self.leave_period.name, | ||
} | ||
create_assignment_for_multiple_employees([employee], frappe._dict(data)) | ||
|
||
make_salary_structure( | ||
"Salary Structure for Encashment", | ||
"Monthly", | ||
employee, | ||
other_details={"leave_encashment_amount_per_day": 50}, | ||
) | ||
|
||
leave_encashment = frappe.get_doc( | ||
{ | ||
"doctype": "Leave Encashment", | ||
"employee": employee, | ||
"leave_type": self.leave_type, | ||
"leave_period": self.leave_period.name, | ||
"encashment_date": self.leave_period.to_date, | ||
"encashment_days": encashment_days, | ||
"currency": "INR", | ||
} | ||
).insert() | ||
leave_encashment.submit() | ||
return leave_encashment |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -347,28 +347,83 @@ def test_mark_absent_for_dates_with_no_attendance_for_midnight_shift(self): | |
shift_type="Test Absent with no Attendance", | ||
start_time="15:00:00", | ||
end_time="23:30:00", | ||
process_attendance_after=add_days(today, -6), | ||
process_attendance_after=add_days(today, -8), | ||
allow_check_out_after_shift_end_time=120, | ||
last_sync_of_checkin=f"{today} 15:00:00", | ||
) | ||
# single day assignment | ||
date1 = add_days(today, -5) | ||
date1 = add_days(today, -7) | ||
make_shift_assignment(shift_type.name, employee, date1, date1) | ||
|
||
# assignment without end date | ||
date2 = add_days(today, -4) | ||
# assignment after a gap | ||
date2 = add_days(today, -5) | ||
make_shift_assignment(shift_type.name, employee, date2, date2) | ||
|
||
# assignment without end date | ||
date3 = add_days(today, -3) | ||
make_shift_assignment(shift_type.name, employee, date3) | ||
|
||
shift_type.process_auto_attendance() | ||
absent_records = frappe.get_all( | ||
"Attendance", | ||
{ | ||
fields=["name", "employee", "attendance_date", "status", "shift"], | ||
filters={ | ||
"attendance_date": ["between", [date1, today]], | ||
"employee": employee, | ||
"status": "Absent", | ||
}, | ||
) | ||
self.assertEqual(len(absent_records), 2) | ||
|
||
self.assertEqual(len(absent_records), 5) | ||
# absent for first assignment | ||
self.assertEqual( | ||
frappe.db.get_value( | ||
"Attendance", | ||
{"attendance_date": date1, "shift": shift_type.name, "employee": employee}, | ||
"status", | ||
), | ||
"Absent", | ||
) | ||
# no attendance for day after first assignment | ||
self.assertIsNone( | ||
frappe.db.get_value( | ||
"Attendance", | ||
{"attendance_date": add_days(date1, 1), "shift": shift_type.name, "employee": employee}, | ||
) | ||
) | ||
# absent for second assignment | ||
self.assertEqual( | ||
frappe.db.get_value( | ||
"Attendance", | ||
{"attendance_date": date2, "shift": shift_type.name, "employee": employee}, | ||
"status", | ||
), | ||
"Absent", | ||
) | ||
# no attendance for day after second assignment | ||
self.assertIsNone( | ||
frappe.db.get_value( | ||
"Attendance", | ||
{"attendance_date": add_days(date2, 1), "shift": shift_type.name, "employee": employee}, | ||
) | ||
) | ||
# absent for third assignment | ||
self.assertEqual( | ||
frappe.db.get_value( | ||
"Attendance", | ||
{"attendance_date": date3, "shift": shift_type.name, "employee": employee}, | ||
"status", | ||
), | ||
"Absent", | ||
) | ||
self.assertEqual( | ||
frappe.db.get_value( | ||
"Attendance", | ||
{"attendance_date": add_days(date3, 1), "shift": shift_type.name, "employee": employee}, | ||
"status", | ||
), | ||
"Absent", | ||
) | ||
|
||
def test_do_not_mark_absent_before_shift_actual_end_time(self): | ||
from hrms.hr.doctype.employee_checkin.test_employee_checkin import make_checkin | ||
|
@@ -612,6 +667,27 @@ def test_skip_auto_attendance_for_overlapping_shift(self): | |
self.assertEqual(log_in.skip_auto_attendance, 1) | ||
self.assertEqual(log_out.skip_auto_attendance, 1) | ||
|
||
def test_mark_attendance_for_default_shift_when_shift_assignment_is_not_overlapping(self): | ||
shift_1 = setup_shift_type(shift_type="Deafult Shift", start_time="08:00:00", end_time="12:00:00") | ||
shift_2 = setup_shift_type(shift_type="Not Default Shift", start_time="10:00:00", end_time="18:00:00") | ||
employee = make_employee( | ||
"[email protected]", company="_Test Company", default_shift=shift_1.name | ||
) | ||
shift_assigned_date = add_days(getdate(), +1) | ||
make_shift_assignment(shift_2.name, employee, shift_assigned_date) | ||
from hrms.hr.doctype.attendance.attendance import mark_attendance | ||
|
||
mark_attendance(employee, add_days(getdate(), -1), "Present", shift=shift_1.name) | ||
shift_1.process_auto_attendance() | ||
self.assertEqual( | ||
frappe.db.get_value( | ||
"Attendance", | ||
{"employee": employee, "attendance_date": getdate(), "shift": shift_1.name}, | ||
"status", | ||
), | ||
"Absent", | ||
) | ||
|
||
|
||
def setup_shift_type(**args): | ||
args = frappe._dict(args) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.