From 2e15e9dae4781af4cd939573c6273d7bea8d216b Mon Sep 17 00:00:00 2001 From: Ali <010109ali@gmail.com> Date: Tue, 5 May 2026 16:39:26 +0000 Subject: [PATCH] =?UTF-8?q?feat(single-declaration):=20compute=20b=C3=B6lm?= =?UTF-8?q?=C9=99=203=20income=20tax=20from=20payroll?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Apply AZ progressive tax brackets (3%/10%/14%) per employee per month on gross pay, then sum for monthly and quarterly tax amounts in bölmə_3 hissə 1. Formula Editor stays responsible for the tax base columns; this fills vergiməbləği* independently. Co-Authored-By: Claude Opus 4.7 (1M context) --- ...lated_to_salaried_and_non_salaried_work.js | 1 + ...lated_to_salaried_and_non_salaried_work.py | 48 +++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/taxes_az/taxes_az/doctype/single_declaration_related_to_salaried_and_non_salaried_work/single_declaration_related_to_salaried_and_non_salaried_work.js b/taxes_az/taxes_az/doctype/single_declaration_related_to_salaried_and_non_salaried_work/single_declaration_related_to_salaried_and_non_salaried_work.js index 89841fa..2a7d838 100644 --- a/taxes_az/taxes_az/doctype/single_declaration_related_to_salaried_and_non_salaried_work/single_declaration_related_to_salaried_and_non_salaried_work.js +++ b/taxes_az/taxes_az/doctype/single_declaration_related_to_salaried_and_non_salaried_work/single_declaration_related_to_salaried_and_non_salaried_work.js @@ -91,6 +91,7 @@ function reload_hisse_1_data(frm) { populate_child_table(frm, 'hissə_2', r.message.hisse_2_data || []); populate_child_table(frm, 'hissə_3', r.message.hisse_3_data || []); update_existing_rows(frm, 'bolme2_hisse1', r.message.bolme2_hisse1_data || {}); + update_existing_rows(frm, 'bölmə_3', r.message.bolme_3_data || {}); populate_child_table(frm, 'vergi_', r.message.vergi_data || []); populate_child_table(frm, 'mdss_', r.message.mdss_data || []); populate_child_table(frm, 'issizlik', r.message.issizlik_data || []); diff --git a/taxes_az/taxes_az/doctype/single_declaration_related_to_salaried_and_non_salaried_work/single_declaration_related_to_salaried_and_non_salaried_work.py b/taxes_az/taxes_az/doctype/single_declaration_related_to_salaried_and_non_salaried_work/single_declaration_related_to_salaried_and_non_salaried_work.py index 311e8f7..217f1b5 100644 --- a/taxes_az/taxes_az/doctype/single_declaration_related_to_salaried_and_non_salaried_work/single_declaration_related_to_salaried_and_non_salaried_work.py +++ b/taxes_az/taxes_az/doctype/single_declaration_related_to_salaried_and_non_salaried_work/single_declaration_related_to_salaried_and_non_salaried_work.py @@ -97,6 +97,7 @@ def populate_declaration_tables(company, year, quarter): hisse_2_data = build_hisse_2(payroll) hisse_3_data = get_absence_data(company, from_date, to_date) bolme2_hisse1_data = get_bolme2_hisse1_data(company, year, quarter) + bolme_3_data = build_bolme_3(payroll, quarter) elave4_data = build_elave4_tables(payroll) return { @@ -105,6 +106,7 @@ def populate_declaration_tables(company, year, quarter): "hisse_2_data": hisse_2_data, "hisse_3_data": hisse_3_data, "bolme2_hisse1_data": bolme2_hisse1_data, + "bolme_3_data": bolme_3_data, **elave4_data, } @@ -285,6 +287,52 @@ def build_elave4_tables(payroll): return output +def _calc_income_tax(gross): + # AZ progressive brackets: 3% / 75 + 10% over 2500 / 625 + 14% over 8000. + # Brackets are per-employee per-month — sum of per-employee taxes ≠ tax on summed base. + if gross <= 0: + return 0.0 + if gross <= 2500: + return gross * 0.03 + if gross <= 8000: + return 75 + (gross - 2500) * 0.10 + return 625 + (gross - 8000) * 0.14 + + +def build_bolme_3(payroll, quarter): + """Income tax (gəlir vergisi) per month, computed per-employee then summed.""" + salary_slips = payroll["salary_slips"] + currency = payroll["currency"] + company_currency = payroll["company_currency"] + + quarter_num = int(quarter[0]) + start_month = (quarter_num - 1) * 3 + 1 + + per_emp_monthly_gross = {} + for ss in salary_slips: + month_index = ss.start_date.month - start_month + 1 + if month_index not in (1, 2, 3): + continue + gp = flt(ss.gross_pay) + if currency == company_currency: + gp *= flt(ss.exchange_rate) + key = (ss.employee, month_index) + per_emp_monthly_gross[key] = per_emp_monthly_gross.get(key, 0.0) + gp + + monthly_tax = {1: 0.0, 2: 0.0, 3: 0.0} + for (_emp, mi), gross in per_emp_monthly_gross.items(): + monthly_tax[mi] += _calc_income_tax(gross) + + return { + "Muzdlu işlə əlaqədar hesablamalar": { + "vergiməbləği": round(monthly_tax[1], 2), + "vergiməbləği2": round(monthly_tax[2], 2), + "vergiməbləği3": round(monthly_tax[3], 2), + "vergiməbləği4": round(monthly_tax[1] + monthly_tax[2] + monthly_tax[3], 2), + } + } + + def get_bolme2_hisse1_data(company, year, quarter): """Build data for bolme2_hisse1: employee counts per month of quarter.""" quarter_num = int(quarter[0]) # "1. Rüb" -> 1