def test_attendance_for_include_holidays(self): # Case 1: leave type with 'Include holidays within leaves as leaves' enabled frappe.delete_doc_if_exists("Leave Type", "Test Include Holidays", force=1) leave_type = frappe.get_doc( dict(leave_type_name="Test Include Holidays", doctype="Leave Type", include_holiday=True)).insert() date = getdate() make_allocation_record(leave_type=leave_type.name, from_date=get_year_start(date), to_date=get_year_ending(date)) employee = get_employee() first_sunday = get_first_sunday(self.holiday_list) leave_application = make_leave_application(employee.name, first_sunday, add_days(first_sunday, 3), leave_type.name) leave_application.reload() self.assertEqual(leave_application.total_leave_days, 4) self.assertEqual( frappe.db.count("Attendance", {"leave_application": leave_application.name}), 4) leave_application.cancel()
def setUp(self): from erpnext.payroll.doctype.salary_slip.test_salary_slip import make_holiday_list from_date = get_year_start(getdate()) to_date = get_year_ending(getdate()) self.holiday_list = make_holiday_list(from_date=from_date, to_date=to_date) frappe.db.delete("Attendance")
def setUp(self): frappe.db.delete("Shift Type") frappe.db.delete("Shift Assignment") frappe.db.delete("Employee Checkin") from_date = get_year_start(getdate()) to_date = get_year_ending(getdate()) self.holiday_list = make_holiday_list(from_date=from_date, to_date=to_date)
def setUp(self): self.employee = make_employee("*****@*****.**", company="_Test Company") frappe.db.delete("Attendance") date = getdate() from_date = get_year_start(date) to_date = get_year_ending(date) make_holiday_list(from_date=from_date, to_date=to_date)
def test_attendance_update_for_exclude_holidays(self): # Case 2: leave type with 'Include holidays within leaves as leaves' disabled frappe.delete_doc_if_exists("Leave Type", "Test Do Not Include Holidays", force=1) leave_type = frappe.get_doc( dict(leave_type_name="Test Do Not Include Holidays", doctype="Leave Type", include_holiday=False)).insert() date = getdate() make_allocation_record(leave_type=leave_type.name, from_date=get_year_start(date), to_date=get_year_ending(date)) employee = get_employee() first_sunday = get_first_sunday(self.holiday_list) # already marked attendance on a holiday should be deleted in this case config = { "doctype": "Attendance", "employee": employee.name, "status": "Present" } attendance_on_holiday = frappe.get_doc(config) attendance_on_holiday.attendance_date = first_sunday attendance_on_holiday.flags.ignore_validate = True attendance_on_holiday.save() # already marked attendance on a non-holiday should be updated attendance = frappe.get_doc(config) attendance.attendance_date = add_days(first_sunday, 3) attendance.flags.ignore_validate = True attendance.save() leave_application = make_leave_application(employee.name, first_sunday, add_days(first_sunday, 3), leave_type.name, employee.company) leave_application.reload() # holiday should be excluded while marking attendance self.assertEqual(leave_application.total_leave_days, 3) self.assertEqual( frappe.db.count("Attendance", {"leave_application": leave_application.name}), 3) # attendance on holiday deleted self.assertFalse( frappe.db.exists("Attendance", attendance_on_holiday.name)) # attendance on non-holiday updated self.assertEqual( frappe.db.get_value("Attendance", attendance.name, "status"), "On Leave")
def load_testdocs(self): from erpnext.accounts.utils import FiscalYearError, get_fiscal_year datapath, _ = os.path.splitext(os.path.realpath(__file__)) with open(datapath + ".json", "r") as fp: docs = json.load(fp) now = getdate() self.from_date = get_first_day(now) self.to_date = get_last_day(now) try: get_fiscal_year(now, company="_T") except FiscalYearError: docs = [ { "companies": [ { "company": "_T", "parent": "_Test Fiscal", "parentfield": "companies", "parenttype": "Fiscal Year", } ], "doctype": "Fiscal Year", "year": "_Test Fiscal", "year_end_date": get_year_ending(now), "year_start_date": get_year_start(now), } ] + docs docs = [ { "abbr": "_T", "company_name": "_T", "country": "United Kingdom", "default_currency": "GBP", "doctype": "Company", "name": "_T", } ] + docs for doc in docs: try: db_doc = frappe.get_doc(doc) if "Invoice" in db_doc.doctype: db_doc.due_date = add_to_date(now, days=1) db_doc.insert() # Create GL Entries: db_doc.submit() else: db_doc.insert(ignore_if_duplicate=True) except frappe.exceptions.DuplicateEntryError: pass
def get_leave_application(employee): now = now_datetime() previous_month = now.month - 1 date = getdate() year_start = getdate(get_year_start(date)) year_end = getdate(get_year_ending(date)) make_allocation_record(employee=employee, from_date=year_start, to_date=year_end) from_date = now.replace(day=7).replace(month=previous_month).date() to_date = now.replace(day=8).replace(month=previous_month).date() return make_leave_application(employee, from_date, to_date, "_Test Leave Type")
def test_validate_application_across_allocations(self): # Test validation for application dates when negative balance is disabled frappe.delete_doc_if_exists("Leave Type", "Test Leave Validation", force=1) leave_type = frappe.get_doc( dict(leave_type_name="Test Leave Validation", doctype="Leave Type", allow_negative=False)).insert() employee = get_employee() date = getdate() first_sunday = get_first_sunday(self.holiday_list, for_date=get_year_start(date)) leave_application = frappe.get_doc( dict( doctype="Leave Application", employee=employee.name, leave_type=leave_type.name, from_date=add_days(first_sunday, 1), to_date=add_days(first_sunday, 4), company="_Test Company", status="Approved", leave_approver="*****@*****.**", )) # Application period cannot be outside leave allocation period self.assertRaises(frappe.ValidationError, leave_application.insert) make_allocation_record(leave_type=leave_type.name, from_date=get_year_start(date), to_date=get_year_ending(date)) leave_application = frappe.get_doc( dict( doctype="Leave Application", employee=employee.name, leave_type=leave_type.name, from_date=add_days(first_sunday, -10), to_date=add_days(first_sunday, 1), company="_Test Company", status="Approved", leave_approver="*****@*****.**", )) # Application period cannot be across two allocation records self.assertRaises(LeaveAcrossAllocationsError, leave_application.insert)
def test_no_shift_fetched_on_holiday_as_per_shift_holiday_list(self): date = getdate() from_date = get_year_start(date) to_date = get_year_ending(date) holiday_list = make_holiday_list(from_date=from_date, to_date=to_date) employee = make_employee("*****@*****.**", company="_Test Company") setup_shift_type(shift_type="Test Holiday Shift", holiday_list=holiday_list) first_sunday = get_first_sunday(holiday_list, for_date=date) timestamp = datetime.combine(first_sunday, get_time("08:00:00")) log = make_checkin(employee, timestamp) self.assertIsNone(log.shift)
def setUp(self): for dt in ["Leave Application", "Leave Allocation", "Salary Slip", "Leave Ledger Entry"]: frappe.db.delete(dt) frappe.set_user("Administrator") set_leave_approver() frappe.db.delete("Attendance", {"employee": "_T-Employee-00001"}) frappe.db.set_value("Employee", "_T-Employee-00001", "holiday_list", "") from_date = get_year_start(getdate()) to_date = get_year_ending(getdate()) self.holiday_list = make_holiday_list(from_date=from_date, to_date=to_date) if not frappe.db.exists("Leave Type", "_Test Leave Type"): frappe.get_doc( dict(leave_type_name="_Test Leave Type", doctype="Leave Type", include_holiday=True) ).insert()
def setUp(self): frappe.db.delete("Leave Period") frappe.db.delete("Leave Policy Assignment") frappe.db.delete("Leave Allocation") frappe.db.delete("Leave Ledger Entry") frappe.db.delete("Additional Salary") frappe.db.delete("Leave Encashment") if not frappe.db.exists("Leave Type", "_Test Leave Type Encashment"): frappe.get_doc(test_records[2]).insert() date = getdate() year_start = getdate(get_year_start(date)) year_end = getdate(get_year_ending(date)) make_holiday_list("_Test Leave Encashment", year_start, year_end) # create the leave policy leave_policy = create_leave_policy( leave_type="_Test Leave Type Encashment", annual_allocation=10 ) leave_policy.submit() # create employee, salary structure and assignment self.employee = make_employee("*****@*****.**", company="_Test Company") self.leave_period = create_leave_period(year_start, year_end, "_Test Company") data = { "assignment_based_on": "Leave Period", "leave_policy": leave_policy.name, "leave_period": self.leave_period.name, } leave_policy_assignments = create_assignment_for_multiple_employees( [self.employee], frappe._dict(data) ) salary_structure = make_salary_structure( "Salary Structure for Encashment", "Monthly", self.employee, other_details={"leave_encashment_amount_per_day": 50}, )
def test_insufficient_leave_balance_validation(self): # CASE 1: Validation when allow negative is disabled frappe.delete_doc_if_exists("Leave Type", "Test Leave Validation", force=1) leave_type = frappe.get_doc( dict(leave_type_name="Test Leave Validation", doctype="Leave Type", allow_negative=False)).insert() employee = get_employee() date = getdate() first_sunday = get_first_sunday(self.holiday_list, for_date=get_year_start(date)) # allocate 2 leaves, apply for more make_allocation_record( leave_type=leave_type.name, from_date=get_year_start(date), to_date=get_year_ending(date), leaves=2, ) leave_application = frappe.get_doc( dict( doctype="Leave Application", employee=employee.name, leave_type=leave_type.name, from_date=add_days(first_sunday, 1), to_date=add_days(first_sunday, 3), company="_Test Company", status="Approved", leave_approver="*****@*****.**", )) self.assertRaises(InsufficientLeaveBalanceError, leave_application.insert) # CASE 2: Allows creating application with a warning message when allow negative is enabled frappe.db.set_value("Leave Type", "Test Leave Validation", "allow_negative", True) make_leave_application(employee.name, add_days(first_sunday, 1), add_days(first_sunday, 3), leave_type.name)
def setUp(self): for dt in [ "Leave Application", "Leave Allocation", "Salary Slip", "Leave Ledger Entry", "Leave Type", ]: frappe.db.delete(dt) frappe.set_user("Administrator") self.employee_id = make_employee("*****@*****.**", company="_Test Company") self.date = getdate() self.year_start = getdate(get_year_start(self.date)) self.year_end = getdate(get_year_ending(self.date)) self.holiday_list = make_holiday_list( "_Test Emp Balance Holiday List", self.year_start, self.year_end )
def test_get_leave_details_for_dashboard(self): employee = get_employee() date = getdate() year_start = getdate(get_year_start(date)) year_end = getdate(get_year_ending(date)) # ALLOCATION = 30 allocation = make_allocation_record(employee=employee.name, from_date=year_start, to_date=year_end) # USED LEAVES = 4 first_sunday = get_first_sunday(self.holiday_list) leave_application = make_leave_application(employee.name, add_days(first_sunday, 1), add_days(first_sunday, 4), "_Test Leave Type") leave_application.reload() # LEAVES PENDING APPROVAL = 1 leave_application = make_leave_application( employee.name, add_days(first_sunday, 5), add_days(first_sunday, 5), "_Test Leave Type", submit=False, ) leave_application.status = "Open" leave_application.save() details = get_leave_details(employee.name, allocation.from_date) leave_allocation = details["leave_allocation"]["_Test Leave Type"] self.assertEqual(leave_allocation["total_leaves"], 30) self.assertEqual(leave_allocation["leaves_taken"], 4) self.assertEqual(leave_allocation["expired_leaves"], 0) self.assertEqual(leave_allocation["leaves_pending_approval"], 1) self.assertEqual(leave_allocation["remaining_leaves"], 26)
def setup_shift_type(**args): args = frappe._dict(args) date = getdate() shift_type = frappe.get_doc( { "doctype": "Shift Type", "__newname": args.shift_type or "_Test Shift", "start_time": "08:00:00", "end_time": "12:00:00", "enable_auto_attendance": 1, "determine_check_in_and_check_out": "Alternating entries as IN and OUT during the same shift", "working_hours_calculation_based_on": "First Check-in and Last Check-out", "begin_check_in_before_shift_start_time": 60, "allow_check_out_after_shift_end_time": 60, "process_attendance_after": add_days(date, -2), "last_sync_of_checkin": now_datetime() + timedelta(days=1), } ) holiday_list = "Employee Checkin Test Holiday List" if not frappe.db.exists("Holiday List", "Employee Checkin Test Holiday List"): holiday_list = frappe.get_doc( { "doctype": "Holiday List", "holiday_list_name": "Employee Checkin Test Holiday List", "from_date": get_year_start(date), "to_date": get_year_ending(date), } ).insert() holiday_list = holiday_list.name shift_type.holiday_list = holiday_list shift_type.update(args) shift_type.save() return shift_type
def test_separate_leave_ledger_entry_for_boundary_applications(self): # When application falls in 2 different allocations and Allow Negative is enabled # creates separate leave ledger entries frappe.delete_doc_if_exists("Leave Type", "Test Leave Validation", force=1) leave_type = frappe.get_doc( dict( leave_type_name="Test Leave Validation", doctype="Leave Type", allow_negative=True, include_holiday=True, ) ).insert() employee = get_employee() date = getdate() year_start = getdate(get_year_start(date)) year_end = getdate(get_year_ending(date)) make_allocation_record(leave_type=leave_type.name, from_date=year_start, to_date=year_end) # application across allocations # CASE 1: from date has no allocation, to date has an allocation / both dates have allocation start_date = add_days(year_start, -10) application = make_leave_application( employee.name, start_date, add_days(year_start, 3), leave_type.name, half_day=1, half_day_date=start_date, ) # 2 separate leave ledger entries ledgers = frappe.db.get_all( "Leave Ledger Entry", {"transaction_type": "Leave Application", "transaction_name": application.name}, ["leaves", "from_date", "to_date"], order_by="from_date", ) self.assertEqual(len(ledgers), 2) self.assertEqual(ledgers[0].from_date, application.from_date) self.assertEqual(ledgers[0].to_date, add_days(year_start, -1)) self.assertEqual(ledgers[1].from_date, year_start) self.assertEqual(ledgers[1].to_date, application.to_date) # CASE 2: from date has an allocation, to date has no allocation application = make_leave_application( employee.name, add_days(year_end, -3), add_days(year_end, 5), leave_type.name ) # 2 separate leave ledger entries ledgers = frappe.db.get_all( "Leave Ledger Entry", {"transaction_type": "Leave Application", "transaction_name": application.name}, ["leaves", "from_date", "to_date"], order_by="from_date", ) self.assertEqual(len(ledgers), 2) self.assertEqual(ledgers[0].from_date, application.from_date) self.assertEqual(ledgers[0].to_date, year_end) self.assertEqual(ledgers[1].from_date, add_days(year_end, 1)) self.assertEqual(ledgers[1].to_date, application.to_date)