frappe / hrms

Open Source HR and Payroll Software
https://frappehr.com
GNU General Public License v3.0
996 stars 555 forks source link

Salary Slip not correctly calculating, leave without pay days or partial paid leave days #129

Open conncampbell opened 1 year ago

conncampbell commented 1 year ago

Information about bug

Duplicate of frappe/erpnext#27975, which went stale, even after I created a pull to fix. :(

Description of the issue

When creating a salary slip that is based on leaves, on a employee with leave days that do not include holidays, the leave without pay is not calculated correctly. In addition, if the leave has partial paid leave, these days are simply added as leave without pay causing the days to be deducted from pay. The leave with pay issue also effects attendance based pay.

Context information (for bug reports)

Payroll settings, "Calculate Payroll Working Days Based On" is set to "Leave" has both issues. Payroll settings, "Calculate Payroll Working Days Based On" is set to "Attendance" has Leave with pay issue.

Output of bench version ERPNext: v13.12.1 (version-13) Frappe Framework: v13.12.1 (version-13)

Steps to reproduce the issue

  1. Set payroll to "leave" or "Attendance"
  2. Create holiday list and apply to employee/company
  3. Create leave type with Partially paid leave enabled and "Include holidays within leaves as leaves" disabled
  4. Create leave policy and apply to employee
  5. Create and approve leave application that spans holidays NEAR THE END OF THE PAYROLL PERIOD. for example, over the last weekend.
  6. Create a Salary slip for employee in period with leave application

Observed result

With payroll settings to Leave based: The Leave Without Pay is not correct (Number of lave days in period). The Payment Days is working days less LWP. The pay component is deducted for the number of Leave without pay days.

With payroll settings to Attendance based: The pay component is deducted for the number of Leave without pay days. The Payment Days is working days less LWP.

Expected result

With payroll settings to Leave based: The Leave Without Pay is correct (Number of non paid leave days in period).
The Payment Days is working days less LWP, but includes the paid leave days. Alternatively, a separate count for paid leave days is show. The pay component is deducted for the number of Leave without pay days only.

With payroll settings to Attendance based: The pay component is deducted for the number of Leave without pay days. The Payment Days is working days less LWP, but includes the paid leave days. Alternatively, a separate count for paid leave days is show. The pay component is deducted for the number of Leave without pay days only.

Additional Information

The problem appears to be related to the salary_slip.py functions calculate_lwp_or_ppl_based_on_leave_application and calculate_lwp_ppl_and_absent_days_based_on_attendance.

calculate_lwp_or_ppl_based_on_leave_application appears to loop using the working days as the index; however the loop doesn't account for holidays and simply works in order from the start date. Instead it should increment past holidays. The current implementation, with 22 working days in a 31 month calendar, will not include holidays past 22 days in the month.

Both functions simply return paid leave days as leave without pay, which is not what is expected. Either they should not include these days as LWP or return them as a separate value.

Module

HR

Version

ERPNext: v13.34.1 (version-13) Frappe Framework: v13.33.1 (version-13)

Installation method

manual install

Relevant log output / Stack trace / Full Error Message.

no error, just incorrect calculation of leave days.
charleslcso commented 1 year ago

I have created another issue a long time ago (25 Jan 2022), and the team doesn't seem to care about the error.

https://github.com/frappe/hrms/issues/116

conncampbell commented 1 year ago

I kinda wonder if payroll is deeply broken, and their awaiting a complete refactor. Considering how much spaghetti payroll and hr code has, I sure hope so.

charleslcso commented 1 year ago

I had to add features to Payroll for my client, and I kinda agree that the functions are scattered in different places. Not to mention bugs and the lack of comprehensive case study. It seems to me that they aim to get it off ground first, and patch patch and more patch - when we report issues.

conncampbell commented 1 year ago

It's a bit sad that these breaking issues with a critical system are left to fester, especially when I believe ERPNext is a excellent product with great potential.

I've created PR for other issues, and they got integrated quickly. Not sure why HR and payroll have issues resolving issues and PR. Perhaps because they are critical systems and their more wary of just anybody's code. Perhaps they used to be less cautious, which is why HR/Payroll is such a mess.

charleslcso commented 1 year ago

Enterprise clients use this kind of app. If calculations are wrong, I have no choice but not to use it.

So bye bye Frappe/ERPNext!

On 28 Oct 2022, at 3:02 PM, Conn Campbell @.***> wrote:

 Information about bug

Duplicate of frappe/erpnext#27975, which went stale, even after I created a pull to fix. :(

Description of the issue

When creating a salary slip that is based on leaves, on a employee with leave days that do not include holidays, the leave without pay is not calculated correctly. In addition, if the leave has partial paid leave, these days are simply added as leave without pay causing the days to be deducted from pay. The leave with pay issue also effects attendance based pay.

Context information (for bug reports)

Payroll settings, "Calculate Payroll Working Days Based On" is set to "Leave" has both issues. Payroll settings, "Calculate Payroll Working Days Based On" is set to "Attendance" has Leave with pay issue.

Output of bench version ERPNext: v13.12.1 (version-13) Frappe Framework: v13.12.1 (version-13)

Steps to reproduce the issue

Set payroll to "leave" or "Attendance" Create holiday list and apply to employee/company Create leave type with Partially paid leave enabled and "Include holidays within leaves as leaves" disabled Create leave policy and apply to employee Create and approve leave application that spans holidays NEAR THE END OF THE PAYROLL PERIOD. for example, over the last weekend. Create a Salary slip for employee in period with leave application Observed result

With payroll settings to Leave based: The Leave Without Pay is not correct (Number of lave days in period). The Payment Days is working days less LWP. The pay component is deducted for the number of Leave without pay days.

With payroll settings to Attendance based: The pay component is deducted for the number of Leave without pay days. The Payment Days is working days less LWP.

Expected result

With payroll settings to Leave based: The Leave Without Pay is correct (Number of non paid leave days in period). The Payment Days is working days less LWP, but includes the paid leave days. Alternatively, a separate count for paid leave days is show. The pay component is deducted for the number of Leave without pay days only.

With payroll settings to Attendance based: The pay component is deducted for the number of Leave without pay days. The Payment Days is working days less LWP, but includes the paid leave days. Alternatively, a separate count for paid leave days is show. The pay component is deducted for the number of Leave without pay days only.

Additional Information

The problem appears to be related to the salary_slip.py functions calculate_lwp_or_ppl_based_on_leave_application and calculate_lwp_ppl_and_absent_days_based_on_attendance.

calculate_lwp_or_ppl_based_on_leave_application appears to loop using the working days as the index; however the loop doesn't account for holidays and simply works in order from the start date. Instead it should increment past holidays. The current implementation, with 22 working days in a 31 month calendar, will not include holidays past 22 days in the month.

Both functions simply return paid leave days as leave without pay, which is not what is expected. Either they should not include these days as LWP or return them as a separate value.

Module

HR

Version

ERPNext: v13.34.1 (version-13) Frappe Framework: v13.33.1 (version-13)

Installation method

manual install

Relevant log output / Stack trace / Full Error Message.

no error, just incorrect calculation of leave days. — Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you commented.

ChandanaSP23 commented 1 year ago

Information about bug

Duplicate of frappe/erpnext#27975, which went stale, even after I created a pull to fix. :(

Description of the issue

When creating a salary slip that is based on leaves, on a employee with leave days that do not include holidays, the leave without pay is not calculated correctly. In addition, if the leave has partial paid leave, these days are simply added as leave without pay causing the days to be deducted from pay. The leave with pay issue also effects attendance based pay.

Context information (for bug reports)

Payroll settings, "Calculate Payroll Working Days Based On" is set to "Leave" has both issues. Payroll settings, "Calculate Payroll Working Days Based On" is set to "Attendance" has Leave with pay issue.

Output of bench version ERPNext: v13.12.1 (version-13) Frappe Framework: v13.12.1 (version-13)

Steps to reproduce the issue

1. Set payroll to "leave" or "Attendance"

2. Create holiday list and apply to employee/company

3. Create leave type with Partially paid leave enabled and  "Include holidays within leaves as leaves" disabled

4. Create leave policy and apply to employee

5. Create and approve leave application that spans holidays NEAR THE END OF THE PAYROLL PERIOD. for example, over the last weekend.

6. Create a Salary slip for employee in period with leave application

Observed result

With payroll settings to Leave based: The Leave Without Pay is not correct (Number of lave days in period). The Payment Days is working days less LWP. The pay component is deducted for the number of Leave without pay days.

With payroll settings to Attendance based: The pay component is deducted for the number of Leave without pay days. The Payment Days is working days less LWP.

Expected result

With payroll settings to Leave based: The Leave Without Pay is correct (Number of non paid leave days in period). The Payment Days is working days less LWP, but includes the paid leave days. Alternatively, a separate count for paid leave days is show. The pay component is deducted for the number of Leave without pay days only.

With payroll settings to Attendance based: The pay component is deducted for the number of Leave without pay days. The Payment Days is working days less LWP, but includes the paid leave days. Alternatively, a separate count for paid leave days is show. The pay component is deducted for the number of Leave without pay days only.

Additional Information

The problem appears to be related to the salary_slip.py functions calculate_lwp_or_ppl_based_on_leave_application and calculate_lwp_ppl_and_absent_days_based_on_attendance.

calculate_lwp_or_ppl_based_on_leave_application appears to loop using the working days as the index; however the loop doesn't account for holidays and simply works in order from the start date. Instead it should increment past holidays. The current implementation, with 22 working days in a 31 month calendar, will not include holidays past 22 days in the month.

Both functions simply return paid leave days as leave without pay, which is not what is expected. Either they should not include these days as LWP or return them as a separate value.

Module

HR

Version

ERPNext: v13.34.1 (version-13) Frappe Framework: v13.33.1 (version-13)

Installation method

manual install

Relevant log output / Stack trace / Full Error Message.

no error, just incorrect calculation of leave days.

Kindly verify this PR for your issue. @conncampbell

conncampbell commented 1 year ago

this is only partially fixed. the LWP calculation is wrong still. the function should be like this:
` def calculate_lwp_or_ppl_based_on_leave_application(self, holidays, working_days): lwp = 0 holidays = "','".join(holidays) daily_wages_fraction_for_half_day = ( flt(frappe.db.get_value("Payroll Settings", None, "daily_wages_fraction_for_half_day")) or 0.5 )

    for d in range(working_days):
        date = add_days(cstr(getdate(self.start_date)), d)
        leave = get_lwp_or_ppl_for_date(date, self.employee, holidays)

        if leave:
            equivalent_lwp_count = 0
            is_half_day_leave = cint(leave[0].is_half_day)
            is_partially_paid_leave = cint(leave[0].is_ppl)
            fraction_of_daily_salary_per_leave = flt(leave[0].fraction_of_daily_salary_per_leave)

            equivalent_lwp_count = (1 - daily_wages_fraction_for_half_day) if is_half_day_leave else 1

            if is_partially_paid_leave:
                equivalent_lwp_count -= equivalent_lwp_count *(
                    fraction_of_daily_salary_per_leave if fraction_of_daily_salary_per_leave else 1
                )

            lwp += equivalent_lwp_count

    return lwp`