From 5bf6e1b16de50d7b0600fbbdd63fa67c0cb96e27 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Tue, 17 Jan 2023 15:10:00 +0530 Subject: [PATCH] feat: get addtional slary for employee --- .../doctype/payroll_period/payroll_period.py | 20 +++-- .../doctype/salary_slip/salary_slip.json | 13 ++- .../doctype/salary_slip/salary_slip.py | 84 +++++++++---------- 3 files changed, 59 insertions(+), 58 deletions(-) diff --git a/hrms/payroll/doctype/payroll_period/payroll_period.py b/hrms/payroll/doctype/payroll_period/payroll_period.py index f3068a115f..26562a651f 100644 --- a/hrms/payroll/doctype/payroll_period/payroll_period.py +++ b/hrms/payroll/doctype/payroll_period/payroll_period.py @@ -80,15 +80,17 @@ def get_payroll_period_days(start_date, end_date, employee, company=None): def get_payroll_period(from_date, to_date, company): - payroll_period = frappe.db.sql( - """ - select name, start_date, end_date - from `tabPayroll Period` - where start_date<=%s and end_date>= %s and company=%s - """, - (from_date, to_date, company), - as_dict=1, - ) + Payroll_Period = frappe.qb.DocType("Payroll Period") + + payroll_period = ( + frappe.qb.from_(Payroll_Period) + .select(Payroll_Period.name, Payroll_Period.start_date, Payroll_Period.end_date) + .where( + (Payroll_Period.start_date <= from_date) + & (Payroll_Period.end_date >= to_date) + & (Payroll_Period.company == company) + ) + ).run(as_dict=1) return payroll_period[0] if payroll_period else None diff --git a/hrms/payroll/doctype/salary_slip/salary_slip.json b/hrms/payroll/doctype/salary_slip/salary_slip.json index 7cd2cf265d..093f5efe22 100644 --- a/hrms/payroll/doctype/salary_slip/salary_slip.json +++ b/hrms/payroll/doctype/salary_slip/salary_slip.json @@ -81,11 +81,12 @@ "ctc", "income_from_other_sources", "total_earnings", - "non_taxable_earnings", "column_break_0rsw", - "deductions_before_tax_calculation", - "tax_exemption_declaration", + "non_taxable_earnings", "standard_tax_exemption_amount", + "tax_exemption_declaration", + "column_break_35wb", + "deductions_before_tax_calculation", "annual_taxable_amount", "income_tax_deducted_till_date", "section_break_75", @@ -699,13 +700,17 @@ "fieldname": "salary_details_tab", "fieldtype": "Tab Break", "label": "Salary Details" + }, + { + "fieldname": "column_break_35wb", + "fieldtype": "Column Break" } ], "icon": "fa fa-file-text", "idx": 9, "is_submittable": 1, "links": [], - "modified": "2023-01-17 13:11:34.478357", + "modified": "2023-01-17 13:32:29.592558", "modified_by": "Administrator", "module": "Payroll", "name": "Salary Slip", diff --git a/hrms/payroll/doctype/salary_slip/salary_slip.py b/hrms/payroll/doctype/salary_slip/salary_slip.py index 32ae671377..3d913697e6 100644 --- a/hrms/payroll/doctype/salary_slip/salary_slip.py +++ b/hrms/payroll/doctype/salary_slip/salary_slip.py @@ -85,6 +85,7 @@ def validate(self): self.compute_month_to_date() self.compute_component_wise_year_to_date() self.add_leave_balances() + self.compute_income_tax_breakup() if frappe.db.get_single_value("Payroll Settings", "max_working_hours_against_timesheet"): max_working_hours = frappe.db.get_single_value( @@ -610,11 +611,10 @@ def set_net_pay(self): flt(self.hour_rate) * flt(self.exchange_rate), self.precision("base_hour_rate") ) self.set_net_total_in_words() - self.set_income_tax_breakup() - def set_income_tax_breakup(self): + def compute_income_tax_breakup(self): self.ctc = self.base_gross_pay * 12 - self.income_from_other_sources = self.income_from_other_sources + self.income_from_other_sources = self.get_income_form_other_sources() self.total_earnings = self.ctc + self.income_from_other_sources self.non_taxable_earnings = 0 self.deductions_before_tax_calculation = 0 @@ -627,14 +627,14 @@ def calculate_component_amounts(self, component_type): if not getattr(self, "_salary_structure_doc", None): self._salary_structure_doc = frappe.get_doc("Salary Structure", self.salary_structure) - payroll_period = get_payroll_period(self.start_date, self.end_date, self.company) + self.payroll_period = get_payroll_period(self.start_date, self.end_date, self.company) self.add_structure_components(component_type) self.add_additional_salary_components(component_type) if component_type == "earnings": - self.add_employee_benefits(payroll_period) + self.add_employee_benefits() else: - self.add_tax_components(payroll_period) + self.add_tax_components() def add_structure_components(self, component_type): data, default_data = self.get_data_for_eval() @@ -756,7 +756,7 @@ def eval_condition_and_formula(self, d, data): ) raise - def add_employee_benefits(self, payroll_period): + def add_employee_benefits(self): for struct_row in self._salary_structure_doc.get("earnings"): if struct_row.is_flexible_benefit == 1: if ( @@ -772,7 +772,7 @@ def add_employee_benefits(self, payroll_period): struct_row.salary_component, self._salary_structure_doc, self.payroll_frequency, - payroll_period, + self.payroll_period, ) if benefit_component_amount: self.update_component_row(struct_row, benefit_component_amount, "earnings") @@ -783,7 +783,7 @@ def add_employee_benefits(self, payroll_period): if benefit_claim_amount: self.update_component_row(struct_row, benefit_claim_amount, "earnings") - self.adjust_benefits_in_last_payroll_period(payroll_period) + self.adjust_benefits_in_last_payroll_period(self.payroll_period) def adjust_benefits_in_last_payroll_period(self, payroll_period): if payroll_period: @@ -811,7 +811,7 @@ def add_additional_salary_components(self, component_type): is_recurring=additional_salary.is_recurring, ) - def add_tax_components(self, payroll_period): + def add_tax_components(self): # Calculate variable_based_on_taxable_salary after all components updated in salary slip tax_components, other_deduction_components = [], [] for d in self._salary_structure_doc.get("deductions"): @@ -828,7 +828,7 @@ def add_tax_components(self, payroll_period): ] for d in tax_components: - tax_amount = self.calculate_variable_based_on_taxable_salary(d, payroll_period) + tax_amount = self.calculate_variable_based_on_taxable_salary(d) tax_row = get_salary_component_data(d) self.update_component_row(tax_row, tax_amount, "deductions") @@ -927,8 +927,8 @@ def set_precision_for_component_amounts(self): for component_row in self.get(component_type): component_row.amount = flt(component_row.amount, component_row.precision("amount")) - def calculate_variable_based_on_taxable_salary(self, tax_component, payroll_period): - if not payroll_period: + def calculate_variable_based_on_taxable_salary(self, tax_component): + if not self.payroll_period: frappe.msgprint( _("Start and end dates not in a valid Payroll Period, cannot calculate {0}.").format( tax_component @@ -937,40 +937,38 @@ def calculate_variable_based_on_taxable_salary(self, tax_component, payroll_peri return # Deduct taxes forcefully for unsubmitted tax exemption proof and unclaimed benefits in the last period - if payroll_period.end_date <= getdate(self.end_date): + if self.payroll_period.end_date <= getdate(self.end_date): self.deduct_tax_for_unsubmitted_tax_exemption_proof = 1 self.deduct_tax_for_unclaimed_employee_benefits = 1 - return self.calculate_variable_tax(payroll_period, tax_component) + return self.calculate_variable_tax(tax_component) - def calculate_variable_tax(self, payroll_period, tax_component): + def calculate_variable_tax(self, tax_component): # get Tax slab from salary structure assignment for the employee and payroll period - tax_slab = self.get_income_tax_slabs(payroll_period) + tax_slab = self.get_income_tax_slabs(self.payroll_period) # get remaining numbers of sub-period (period for which one salary is processed) remaining_sub_periods = get_period_factor( - self.employee, self.start_date, self.end_date, self.payroll_frequency, payroll_period + self.employee, self.start_date, self.end_date, self.payroll_frequency, self.payroll_period )[1] # get taxable_earnings, opening_taxable_earning, paid_taxes for previous period previous_taxable_earnings = self.get_taxable_earnings_for_prev_period( - payroll_period.start_date, self.start_date, tax_slab.allow_tax_exemption + self.payroll_period.start_date, self.start_date, tax_slab.allow_tax_exemption ) previous_total_paid_taxes = self.get_tax_paid_in_period( - payroll_period.start_date, self.start_date, tax_component + self.payroll_period.start_date, self.start_date, tax_component ) # get taxable_earnings for current period (all days) - current_taxable_earnings = self.get_taxable_earnings( - tax_slab.allow_tax_exemption, payroll_period=payroll_period - ) + current_taxable_earnings = self.get_taxable_earnings(tax_slab.allow_tax_exemption) future_structured_taxable_earnings = current_taxable_earnings.taxable_earnings * ( math.ceil(remaining_sub_periods) - 1 ) # get taxable_earnings, addition_earnings for current actual payment days current_taxable_earnings_for_payment_days = self.get_taxable_earnings( - tax_slab.allow_tax_exemption, based_on_payment_days=1, payroll_period=payroll_period + tax_slab.allow_tax_exemption, based_on_payment_days=1 ) current_structured_taxable_earnings = current_taxable_earnings_for_payment_days.taxable_earnings current_additional_earnings = current_taxable_earnings_for_payment_days.additional_income @@ -981,14 +979,14 @@ def calculate_variable_tax(self, payroll_period, tax_component): # Get taxable unclaimed benefits unclaimed_taxable_benefits = 0 if self.deduct_tax_for_unclaimed_employee_benefits: - unclaimed_taxable_benefits = self.calculate_unclaimed_taxable_benefits(payroll_period) + unclaimed_taxable_benefits = self.calculate_unclaimed_taxable_benefits() unclaimed_taxable_benefits += current_taxable_earnings_for_payment_days.flexi_benefits # Total exemption amount based on tax exemption declaration - total_exemption_amount = self.get_total_exemption_amount(payroll_period, tax_slab) + total_exemption_amount = self.get_total_exemption_amount(tax_slab) # Employee Other Incomes - other_incomes = self.get_income_form_other_sources(payroll_period) or 0.0 + other_incomes = self.get_income_form_other_sources() or 0.0 # Total taxable earnings including additional and other incomes total_taxable_earnings = ( @@ -1148,9 +1146,7 @@ def get_tax_paid_in_period(self, start_date, end_date, tax_component): return total_tax_paid + tax_deducted_till_date - def get_taxable_earnings( - self, allow_tax_exemption=False, based_on_payment_days=0, payroll_period=None - ): + def get_taxable_earnings(self, allow_tax_exemption=False, based_on_payment_days=0): joining_date, relieving_date = self.get_joining_and_relieving_dates() taxable_earnings = 0 @@ -1179,7 +1175,7 @@ def get_taxable_earnings( # Get additional amount based on future recurring additional salary if additional_amount and earning.is_recurring_additional_salary: additional_income += self.get_future_recurring_additional_amount( - earning.additional_salary, earning.additional_amount, payroll_period + earning.additional_salary, earning.additional_amount ) # Used earning.additional_amount to consider the amount for the full month if earning.deduct_full_tax_on_selected_payroll_date: @@ -1199,7 +1195,7 @@ def get_taxable_earnings( if additional_amount and ded.is_recurring_additional_salary: additional_income -= self.get_future_recurring_additional_amount( - ded.additional_salary, ded.additional_amount, payroll_period + ded.additional_salary, ded.additional_amount ) # Used ded.additional_amount to consider the amount for the full month return frappe._dict( @@ -1211,9 +1207,7 @@ def get_taxable_earnings( } ) - def get_future_recurring_additional_amount( - self, additional_salary, monthly_additional_amount, payroll_period - ): + def get_future_recurring_additional_amount(self, additional_salary, monthly_additional_amount): future_recurring_additional_amount = 0 to_date = frappe.db.get_value("Additional Salary", additional_salary, "to_date") @@ -1222,8 +1216,8 @@ def get_future_recurring_additional_amount( # If recurring period end date is beyond the payroll period, # last day of payroll period should be considered for recurring period calculation - if getdate(to_date) > getdate(payroll_period.end_date): - to_date = getdate(payroll_period.end_date) + if getdate(to_date) > getdate(self.payroll_period.end_date): + to_date = getdate(self.payroll_period.end_date) future_recurring_period = ((to_date.year - from_date.year) * 12) + ( to_date.month - from_date.month @@ -1283,7 +1277,7 @@ def get_amount_based_on_payment_days(self, row, joining_date, relieving_date): return amount, additional_amount - def calculate_unclaimed_taxable_benefits(self, payroll_period): + def calculate_unclaimed_taxable_benefits(self): # get total sum of benefits paid total_benefits_paid = flt( frappe.db.sql( @@ -1301,7 +1295,7 @@ def calculate_unclaimed_taxable_benefits(self, payroll_period): """, { "employee": self.employee, - "start_date": payroll_period.start_date, + "start_date": self.payroll_period.start_date, "end_date": self.start_date, }, )[0][0] @@ -1318,19 +1312,19 @@ def calculate_unclaimed_taxable_benefits(self, payroll_period): and employee=%s and claim_date between %s and %s """, - (self.employee, payroll_period.start_date, self.end_date), + (self.employee, self.payroll_period.start_date, self.end_date), )[0][0] ) return total_benefits_paid - total_benefits_claimed - def get_total_exemption_amount(self, payroll_period, tax_slab): + def get_total_exemption_amount(self, tax_slab): total_exemption_amount = 0 if tax_slab.allow_tax_exemption: if self.deduct_tax_for_unsubmitted_tax_exemption_proof: exemption_proof = frappe.db.get_value( "Employee Tax Exemption Proof Submission", - {"employee": self.employee, "payroll_period": payroll_period.name, "docstatus": 1}, + {"employee": self.employee, "payroll_period": self.payroll_period.name, "docstatus": 1}, ["exemption_amount"], ) if exemption_proof: @@ -1338,7 +1332,7 @@ def get_total_exemption_amount(self, payroll_period, tax_slab): else: declaration = frappe.db.get_value( "Employee Tax Exemption Declaration", - {"employee": self.employee, "payroll_period": payroll_period.name, "docstatus": 1}, + {"employee": self.employee, "payroll_period": self.payroll_period.name, "docstatus": 1}, ["total_exemption_amount"], ) if declaration: @@ -1348,12 +1342,12 @@ def get_total_exemption_amount(self, payroll_period, tax_slab): return total_exemption_amount - def get_income_form_other_sources(self, payroll_period): + def get_income_form_other_sources(self): return frappe.get_all( "Employee Other Income", filters={ "employee": self.employee, - "payroll_period": payroll_period.name, + "payroll_period": self.payroll_period.name, "company": self.company, "docstatus": 1, },