def get_max_benefits(employee, on_date): sal_struct = get_assigned_salary_structure(employee, on_date) if sal_struct: max_benefits = frappe.db.get_value("Salary Structure", sal_struct, "max_benefits") if max_benefits > 0: return max_benefits return False
def validate_non_pro_rata_benefit_claim(self, max_benefits, payroll_period): claimed_amount = self.claimed_amount pro_rata_amount = self.get_pro_rata_amount_in_application( payroll_period.name) if not pro_rata_amount: pro_rata_amount = 0 # Get pro_rata_amount if there is no application, # get salary structure for the date and calculate pro-rata amount sal_struct_name = get_assigned_salary_structure( self.employee, self.claim_date) if sal_struct_name: sal_struct = frappe.get_doc("Salary Structure", sal_struct_name) pro_rata_amount = get_benefit_pro_rata_ratio_amount( self.employee, self.claim_date, sal_struct) claimed_amount += get_previous_claimed_amount(self.employee, payroll_period, non_pro_rata=True) if max_benefits < pro_rata_amount + claimed_amount: frappe.throw( _("Maximum benefit of employee {0} exceeds {1} by the sum {2} of benefit application pro-rata component\ amount and previous claimed amount").format( self.employee, max_benefits, pro_rata_amount + claimed_amount - max_benefits))
def validate_remaining_benefit_amount(self): # check salary structure earnings have flexi component (sum of max_benefit_amount) # without pro-rata which satisfy the remaining_benefit # else pro-rata component for the amount # again comes the same validation and satisfy or throw benefit_components = [] if self.employee_benefits: for employee_benefit in self.employee_benefits: benefit_components.append(employee_benefit.earning_component) salary_struct_name = get_assigned_salary_structure(self.employee, self.date) if salary_struct_name: non_pro_rata_amount = 0 pro_rata_amount = 0 salary_structure = frappe.get_doc("Salary Structure", salary_struct_name) if salary_structure.earnings: for earnings in salary_structure.earnings: if earnings.is_flexible_benefit == 1 and earnings.salary_component not in benefit_components: pay_against_benefit_claim, max_benefit_amount = frappe.db.get_value("Salary Component", earnings.salary_component, ["pay_against_benefit_claim", "max_benefit_amount"]) if pay_against_benefit_claim != 1: pro_rata_amount += max_benefit_amount else: non_pro_rata_amount += max_benefit_amount if pro_rata_amount == 0 and non_pro_rata_amount == 0: frappe.throw(_("Please add the remaining benefits {0} to any of the existing component").format(self.remaining_benefit)) elif non_pro_rata_amount > 0 and non_pro_rata_amount < rounded(self.remaining_benefit): frappe.throw(_("You can claim only an amount of {0}, the rest amount {1} should be in the application \ as pro-rata component").format(non_pro_rata_amount, self.remaining_benefit - non_pro_rata_amount)) elif non_pro_rata_amount == 0: frappe.throw(_("Please add the remaining benefits {0} to the application as \ pro-rata component").format(self.remaining_benefit))
def get_leave_details_for_encashment(self): salary_structure = get_assigned_salary_structure( self.employee, self.encashment_date or getdate(nowdate())) if not salary_structure: frappe.throw( _("No Salary Structure assigned for Employee {0} on given date {1}" ).format(self.employee, self.encashment_date)) if not frappe.db.get_value("Leave Type", self.leave_type, 'allow_encashment'): frappe.throw( _("Leave Type {0} is not encashable").format(self.leave_type)) allocation = self.get_leave_allocation() if not allocation: frappe.throw( _("No Leaves Allocated to Employee: {0} for Leave Type: {1}"). format(self.employee, self.leave_type)) self.leave_balance = allocation.total_leaves_allocated - allocation.carry_forwarded_leaves_count\ - get_unused_leaves(self.employee, self.leave_type, allocation.from_date, self.encashment_date) encashable_days = self.leave_balance - frappe.db.get_value( 'Leave Type', self.leave_type, 'encashment_threshold_days') self.encashable_days = encashable_days if encashable_days > 0 else 0 per_day_encashment = frappe.db.get_value( 'Salary Structure', salary_structure, 'leave_encashment_amount_per_day') self.encashment_amount = self.encashable_days * per_day_encashment if per_day_encashment > 0 else 0 self.leave_allocation = allocation.name return True
def get_leave_details_for_encashment(self): salary_structure = get_assigned_salary_structure( self.employee, self.encashment_date or getdate(nowdate())) if not salary_structure: frappe.throw( _("No Salary Structure assigned for Employee {0} on given date {1}" ).format(self.employee, self.encashment_date)) if not frappe.db.get_value("Leave Type", self.leave_type, 'allow_encashment'): frappe.throw( _("Leave Type {0} is not encashable").format(self.leave_type)) self.leave_balance = get_leave_balance_on( self.employee, self.leave_type, self.encashment_date or getdate(nowdate()), consider_all_leaves_in_the_allocation_period=True) encashable_days = self.leave_balance - frappe.db.get_value( 'Leave Type', self.leave_type, 'encashment_threshold_days') self.encashable_days = encashable_days if encashable_days > 0 else 0 per_day_encashment = frappe.db.get_value( 'Salary Structure', salary_structure, 'leave_encashment_amount_per_day') self.encashment_amount = self.encashable_days * per_day_encashment if per_day_encashment > 0 else 0 self.leave_allocation = self.get_leave_allocation() return True
def get_employee_charge_per_hour(self, employee): salary_structure = get_assigned_salary_structure( employee.name, today()) if not salary_structure: return 0.0 salary_structure = frappe.get_doc("Salary Structure", salary_structure) if salary_structure.docstatus != 1 or not salary_structure.is_active == "Yes" or \ not salary_structure.salary_slip_based_on_timesheet: return 0.0 return salary_structure.hour_rate
def create_leave_encashment(leave_allocation): ''' Creates leave encashment for the given allocations ''' for allocation in leave_allocation: if not get_assigned_salary_structure(allocation.employee, allocation.to_date): continue leave_encashment = frappe.get_doc( dict(doctype="Leave Encashment", leave_period=allocation.leave_period, employee=allocation.employee, leave_type=allocation.leave_type, encashment_date=allocation.to_date)) leave_encashment.insert(ignore_permissions=True)
def get_earning_components(doctype, txt, searchfield, start, page_len, filters): if len(filters) < 2: return {} salary_structure = get_assigned_salary_structure(filters['employee'], filters['date']) if salary_structure: return frappe.db.sql(""" select salary_component from `tabSalary Detail` where parent = %s and is_flexible_benefit = 1 order by name """, salary_structure) else: frappe.throw(_("Salary Structure not found for employee {0} and date {1}") .format(filters['employee'], filters['date']))
def validate_non_pro_rata_benefit_claim(self, max_benefits, payroll_period): claimed_amount = self.claimed_amount pro_rata_amount = self.get_pro_rata_amount_in_application(payroll_period.name) if not pro_rata_amount: pro_rata_amount = 0 # Get pro_rata_amount if there is no application, # get salary structure for the date and calculate pro-rata amount sal_struct_name = get_assigned_salary_structure(self.employee, self.claim_date) if sal_struct_name: sal_struct = frappe.get_doc("Salary Structure", sal_struct_name) pro_rata_amount = get_benefit_pro_rata_ratio_amount(self.employee, self.claim_date, sal_struct) claimed_amount += get_previous_claimed_amount(self.employee, payroll_period, non_pro_rata = True) if max_benefits < pro_rata_amount + claimed_amount: frappe.throw(_("Maximum benefit of employee {0} exceeds {1} by the sum {2} of benefit application pro-rata component\ amount and previous claimed amount").format(self.employee, max_benefits, pro_rata_amount+claimed_amount-max_benefits))
def get_worked_hours(self): attendance = frappe.db.sql( "select actual_working_hours_work from `tabAttendance` where employee='{0}' and attendance_date between '{1}' and '{2}' and docstatus=1 " .format(self.employee, self.start_date, self.end_date)) absent_hours = 0 absent_days = frappe.db.sql( "select count(name) from `tabAttendance` where employee='{0}' and status='Absent' and attendance_date between '{1}' and '{2}' and docstatus=1 " .format(self.employee, self.start_date, self.end_date))[0][0] if absent_days >= 5: absent_days = absent_days + calendar.FRIDAY absent_hours = absent_days * 8 salary_structure = get_assigned_salary_structure( self.employee, self.end_date or getdate(nowdate())) if salary_structure: salary = frappe.db.sql( "select amount from `tabSalary Detail` where parenttype='Salary Structure' and salary_component='Basic' and parent='{0}'" .format(salary_structure)) if salary: emp_salary = salary[0][0] else: emp_salary = 0 hours = 0 minutes = 0 hour_rate = 0 i = 1 if attendance[0][0]: for day_working_hours in attendance: hours += flt(day_working_hours[0].split(":")[0]) minutes += flt(day_working_hours[0].split(":")[1]) while i == 1: if minutes >= 60: hours = hours + 1 minutes = minutes - 60 else: if minutes >= 30: hours = hours + 1 i = 0 self.current_month_worked_hours = hours - absent_hours self.hour_rate_work = emp_salary / 30 self.hours_diff = self.monthly_total_hours - self.current_month_worked_hours self.total_deduction_hours = self.hours_diff * self.hour_rate_work * -1
def get_earning_components(doctype, txt, searchfield, start, page_len, filters): if len(filters) < 2: return {} employee = filters['employee'] date = filters['date'] salary_structure = get_assigned_salary_structure(employee, date) if salary_structure: query = """select salary_component from `tabSalary Detail` where parent = '{salary_structure}' and is_flexible_benefit = 1 order by name""" return frappe.db.sql( query.format(**{"salary_structure": salary_structure})) return {}
def get_earning_components(doctype, txt, searchfield, start, page_len, filters): if len(filters) < 2: return {} employee = filters['employee'] date = filters['date'] salary_structure = get_assigned_salary_structure(employee, date) if salary_structure: query = """select salary_component from `tabSalary Detail` where parent = '{salary_structure}' and is_flexible_benefit = 1 order by name""" return frappe.db.sql(query.format(**{ "salary_structure": salary_structure })) return {}
def get_max_benefits_remaining(employee, on_date, payroll_period): max_benefits = get_max_benefits(employee, on_date) if max_benefits and max_benefits > 0: have_depends_on_payment_days = False per_day_amount_total = 0 payroll_period_days = get_payroll_period_days(on_date, on_date, employee)[0] payroll_period_obj = frappe.get_doc("Payroll Period", payroll_period) # Get all salary slip flexi amount in the payroll period prev_sal_slip_flexi_total = get_sal_slip_total_benefit_given( employee, payroll_period_obj) if prev_sal_slip_flexi_total > 0: # Check salary structure hold depends_on_payment_days component # If yes then find the amount per day of each component and find the sum sal_struct_name = get_assigned_salary_structure(employee, on_date) if sal_struct_name: sal_struct = frappe.get_doc("Salary Structure", sal_struct_name) for sal_struct_row in sal_struct.get("earnings"): salary_component = frappe.get_doc( "Salary Component", sal_struct_row.salary_component) if salary_component.depends_on_payment_days == 1 and salary_component.pay_against_benefit_claim != 1: have_depends_on_payment_days = True benefit_amount = get_benefit_pro_rata_ratio_amount( sal_struct, salary_component.max_benefit_amount) amount_per_day = benefit_amount / payroll_period_days per_day_amount_total += amount_per_day # Then the sum multiply with the no of lwp in that period # Include that amount to the prev_sal_slip_flexi_total to get the actual if have_depends_on_payment_days and per_day_amount_total > 0: holidays = get_holidays_for_employee( employee, payroll_period_obj.start_date, on_date) working_days = date_diff(on_date, payroll_period_obj.start_date) + 1 leave_days = calculate_lwp(employee, payroll_period_obj.start_date, holidays, working_days) leave_days_amount = leave_days * per_day_amount_total prev_sal_slip_flexi_total += leave_days_amount return max_benefits - prev_sal_slip_flexi_total return max_benefits
def update_hourly_costs(self): """ Called from update_costs button. Get the hour rate from assigned salary structure Set to hourly cost Update costs :return: """ for detail in self.details: hourly_cost = 0.00 salary_structure = get_assigned_salary_structure( detail.employee, today()) if salary_structure: hour_rate = frappe.db.get_value('Salary Structure', salary_structure, 'hour_rate') hourly_cost = hour_rate detail.hourly_cost = hourly_cost
def get_leave_details_for_encashment(self): salary_structure = get_assigned_salary_structure(self.employee, self.encashment_date or getdate(nowdate())) if not salary_structure: frappe.throw(_("No Salary Structure assigned for Employee {0} on given date {1}").format(self.employee, self.encashment_date)) if not frappe.db.get_value("Leave Type", self.leave_type, 'allow_encashment'): frappe.throw(_("Leave Type {0} is not encashable").format(self.leave_type)) self.leave_balance = get_leave_balance_on(self.employee, self.leave_type, self.encashment_date or getdate(nowdate()), consider_all_leaves_in_the_allocation_period=True) encashable_days = self.leave_balance - frappe.db.get_value('Leave Type', self.leave_type, 'encashment_threshold_days') self.encashable_days = encashable_days if encashable_days > 0 else 0 per_day_encashment = frappe.db.get_value('Salary Structure', salary_structure , 'leave_encashment_amount_per_day') self.encashment_amount = self.encashable_days * per_day_encashment if per_day_encashment > 0 else 0 self.leave_allocation = self.get_leave_allocation() return True
def get_max_benefits_remaining(employee, on_date, payroll_period): max_benefits = get_max_benefits(employee, on_date) if max_benefits and max_benefits > 0: have_depends_on_payment_days = False per_day_amount_total = 0 payroll_period_days = get_payroll_period_days(on_date, on_date, employee)[0] payroll_period_obj = frappe.get_doc("Payroll Period", payroll_period) # Get all salary slip flexi amount in the payroll period prev_sal_slip_flexi_total = get_sal_slip_total_benefit_given(employee, payroll_period_obj) if prev_sal_slip_flexi_total > 0: # Check salary structure hold depends_on_payment_days component # If yes then find the amount per day of each component and find the sum sal_struct_name = get_assigned_salary_structure(employee, on_date) if sal_struct_name: sal_struct = frappe.get_doc("Salary Structure", sal_struct_name) for sal_struct_row in sal_struct.get("earnings"): salary_component = frappe.get_doc("Salary Component", sal_struct_row.salary_component) if salary_component.depends_on_payment_days == 1 and salary_component.pay_against_benefit_claim != 1: have_depends_on_payment_days = True benefit_amount = get_benefit_pro_rata_ratio_amount(sal_struct, salary_component.max_benefit_amount) amount_per_day = benefit_amount / payroll_period_days per_day_amount_total += amount_per_day # Then the sum multiply with the no of lwp in that period # Include that amount to the prev_sal_slip_flexi_total to get the actual if have_depends_on_payment_days and per_day_amount_total > 0: holidays = get_holidays_for_employee(employee, payroll_period_obj.start_date, on_date) working_days = date_diff(on_date, payroll_period_obj.start_date) + 1 leave_days = calculate_lwp(employee, payroll_period_obj.start_date, holidays, working_days) leave_days_amount = leave_days * per_day_amount_total prev_sal_slip_flexi_total += leave_days_amount return max_benefits - prev_sal_slip_flexi_total return max_benefits
def get_leave_details_for_encashment(self, current_days=0.0, encashment_amount=0.0): self.encasha_amount_from_out = encashment_amount self.salary_structure = get_assigned_salary_structure( self.employee, self.encashment_date or getdate(nowdate())) if not self.salary_structure: frappe.throw( _("No Salary Structure assigned for Employee {0} on given date {1}" ).format(self.employee, self.encashment_date)) if not frappe.db.get_value("Leave Type", self.leave_type, 'allow_encashment'): frappe.throw( _("Leave Type {0} is not encashable").format(self.leave_type)) self.leave_balance = get_leave_balance_on( self.employee, self.leave_type, self.encashment_date or getdate(nowdate()), consider_all_leaves_in_the_allocation_period=True) if flt(current_days) > 0: encashable_days = current_days self.encashable_days_from_out = current_days else: encashable_days = ((self.leave_balance - frappe.db.get_value( 'Leave Type', self.leave_type, 'encashment_threshold_days')) if self.encashable_days_from_out == 0.0 else self.encashable_days_from_out) # frappe.msgprint(str(self.encashment_amount)) if encashment_amount == None: #or encashment_amount != self.encashment_amount: self.encashable_days = flt( encashable_days) if flt(encashable_days) > 0 else 0 day_calculation = 360 # frappe.db.get_single_value("HR Settings", "day_calculation") if day_calculation == "Calendar": day_calculation = "365" day_percentage = 12 / flt(day_calculation) per_day_encashment = 0.0 data = self.get_data_for_eval() salary_components = data["salary_components"] # frappe.msgprint(str(salary_components)) for key in salary_components: check_add = frappe.db.get_value( "Salary Component", key["salary_component"], "include_in_leave_encashment_") if check_add == 1: if key["amount_based_on_formula"] == 1 and key[ "amount_based_on_func"] == 0: formula = key["formula"].strip( ) if key["formula"] else None if formula: # frappe.msgprint(str(formula)) per_day_encashment += frappe.safe_eval( formula, self.whitelisted_globals, data) elif key["amount_based_on_func"] == 0: per_day_encashment += flt(key["amount"]) self.encashment_amount = self.encashable_days * day_percentage * per_day_encashment if per_day_encashment > 0 else 0 else: self.encashment_amount = encashment_amount self.leave_allocation = self.get_leave_allocation() return True