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()
Beispiel #2
0
	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")
Beispiel #3
0
    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)
Beispiel #4
0
    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")
Beispiel #6
0
	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
Beispiel #7
0
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)
Beispiel #9
0
    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)
Beispiel #15
0
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)