phamos-eu / HR-Addon

HR Add-on for ERPNext
Other
18 stars 38 forks source link

Bulk Generation of Workdays - is not working if not all employees are maintained or doesnt't need this time collection #85

Open ReachyBayern opened 2 months ago

ReachyBayern commented 2 months ago

current problem:

the bulk generation could not be filtered by shift_types or departments or companies. We have teams, which are working outside at customers and they tell the checkin times some days later. Or we have different companies and departments which should generate workdays separately with the bulk transaction for there teams.

Proposal:

Generating wokdays in bulk transaktion by selecting employees by:

for now first 2 points we soved by modifying original programming (workday.py and hr_addon_settings.py). But this is just a fast & dirty, temporarily solution... Otherwise we could start setup checkin and out in steps for all employees.

wojosc commented 2 months ago

@reggaetuna

ReachyBayern commented 2 months ago

our temporarily solution in workday.py. here is also included the topic regarding compensatory_off --> target_hours = 0 our changes are highlighted bold:

def process_bulk_workday(data):
    '''bulk workday processing'''
    import json
    if isinstance(data, str):
        data = json.loads(data)
    data = frappe._dict(data)
    company = frappe.get_value('Employee', data.employee, 'company')
    check_wwh = frappe.db.get_list("Weekly Working Hours", distinct=True, filters={"employee": data.employee}, fields=["employee"], order_by="employee")
    if check_wwh:
        if not data.unmarked_days:
            # frappe.throw(_("Please select a date"))
            return

        for date in data.unmarked_days:
            current_date = get_datetime(date)
            check_wwh = frappe.db.get_list("Weekly Working Hours", distinct=True, filters={"employee": data.employee, "valid_from": ["<=", current_date],"valid_to": [">=",current_date]}, fields=["employee"], order_by="employee")
            if check_wwh:
                single = []
                #single = view_actual_employee_log(data.employee, get_datetime(date))
                single = get_actual_employee_log_bulk(data.employee, get_datetime(date))
                c_single = single[0]["items"]       
                doc_dict = {
                    'doctype': 'Workday',
                    'employee': data.employee,
                    'log_date': get_datetime(date),
                    'company': company,
                    'attendance':single[0]["attendance"],
                    'hours_worked':"{:.2f}".format(single[0]["ahour"]/(60*60)),
                    'break_hours': "{:.2f}".format(single[0]["bhour"]/(60*60)),
                    'expected_break_hours': "{:.2f}".format(single[0]["break_minutes"]/(60)),
                    'total_work_seconds':single[0]["ahour"],
                    'total_break_seconds':single[0]["bhour"],
                    'actual_working_hours': "{:.2f}".format(single[0]["ahour"]/(60*60) - single[0]["break_minutes"]/60)
                }
                workday = frappe.get_doc(doc_dict).insert()
                target_hours = single[0]["thour"]
                if (workday.status == 'Half Day'):
                    target_hours = (single[0]["thour"])/2
                **if (workday.status == 'On Leave' and workday.custom_leave_type != 'Compensatory Off' ):**
                    target_hours = 0
                workday.target_hours = target_hours
                workday.total_target_seconds = target_hours*(60*60)

                if workday.target_hours == 0:
                    workday.expected_break_hours = 0
                    workday.total_break_seconds = 0
                    # workday.actual_working_hours = 0
                if float(workday.hours_worked) < 6:
                    wwh = frappe.db.get_list(doctype="Weekly Working Hours", filters={"employee": workday.employee}, fields=["name", "no_break_hours"])
                    no_break_hours = True if len(wwh) > 0 and wwh[0]["no_break_hours"] == 1 else False
                    if no_break_hours:
                        workday.expected_break_hours = 0
                        workday.total_break_seconds = 0
                        workday.actual_working_hours = workday.hours_worked

                # lenght of single must be greater than zero
                if((not single[0]["items"] is None) and (len(single[0]["items"]) > 0)):
                    workday.first_checkin = c_single[0].time
                    workday.last_checkout = c_single[-1].time

                    for i in range(len(c_single)):
                        row = workday.append("employee_checkins", {
                            'employee_checkin': c_single[i]["name"],
                            'log_type': c_single[i]["log_type"],
                            'log_time': c_single[i]["time"],
                            'skip_auto_attendance': c_single[i]["skip_auto_attendance"],
                            'parent':workday
                        })
                if date_is_in_holiday_list(data.employee, get_datetime(date)):
                    wwh = frappe.db.get_list(doctype="Weekly Working Hours", filters={"employee": data.employee}, fields=["name", "no_break_hours", "set_target_hours_to_zero_when_date_is_holiday"])
                    if len(wwh) > 0 and wwh[0]["set_target_hours_to_zero_when_date_is_holiday"] == 1:
                        workday.actual_working_hours = float(workday.actual_working_hours) + float(workday.expected_break_hours)
                        workday.expected_break_hours = 0
                        workday.target_hours = 0
                        workday.total_target_seconds = 0

                #workday.submit() 
                workday.save()

hr_addon_settings.py:

@frappe.whitelist()
def generate_workdays_for_past_7_days_now():
    today = frappe.utils.datetime.datetime.now()
    a_week_ago = today - frappe.utils.datetime.timedelta(days=7)
    # employees = frappe.db.get_list("Employee")
    employees = frappe.db.get_list("Shift Assignment",fields=['employee'], filters={'status':'Active'}, order_by='employee')
    for employee in employees:
        #employee_name = employee["name"]
        employee_name = employee["employee"]
        unmarked_days = get_unmarked_range(employee_name, a_week_ago.strftime("%Y-%m-%d"), today.strftime("%Y-%m-%d"))
        data = {
            "employee": employee_name,
            "unmarked_days": unmarked_days
        }
        process_bulk_workday(data)