From 671b2195fe0aeb5aa2e9e6369fe6c4cae6406d0e Mon Sep 17 00:00:00 2001 From: Ali <010109ali@gmail.com> Date: Mon, 11 May 2026 15:52:28 +0000 Subject: [PATCH] feat(employee-payroll-register): add per-contribution columns net of exemption MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For each social contribution (DSMF, İcbari tibbi sığorta, İşsizlikdən sığorta — işçi and şirkət, everything except Gəlir vergisi) add a column per month that recomputes the amount on gross_pay minus that contribution's "cəlb olunmayan gəlir" amount, using the Salary Component formula. Sits next to the original column. 18 new columns total. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../employee_payroll_register.py | 44 +++++++++++++++---- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/taxes_az/taxes_az/report/employee_payroll_register/employee_payroll_register.py b/taxes_az/taxes_az/report/employee_payroll_register/employee_payroll_register.py index 74d2abd..d3081c3 100644 --- a/taxes_az/taxes_az/report/employee_payroll_register/employee_payroll_register.py +++ b/taxes_az/taxes_az/report/employee_payroll_register/employee_payroll_register.py @@ -35,6 +35,18 @@ DEDUCTION_TYPES = [ EH_COMPONENT = "Əsas əmək haqqı" MK_COMPONENT = "Məzuniyyət Kompensasiyası" +# Social-contribution deductions (everything except Gəlir vergisi) get an extra +# column per month: the contribution recomputed on gross_pay net of its own +# "cəlb olunmayan gəlir" amount. Maps deduction name → Salary Slip exempt field. +CONTRIBUTION_EXEMPT_FIELD = { + "DSMF (işçi)": "custom_mdss_amount", + "DSMF (şirkət)": "custom_mdss_amount", + "İcbari tibbi sığorta (işçi 2%)": "custom_medical_insurance_amount", + "İcbari tibbi sığorta (şirkət 2%)": "custom_medical_insurance_amount", + "İşsizlikdən sığorta haqqı (işçi 0,5%)": "custom_unemployment_insurance_amount", + "İşsizlikdən sığorta haqqı (şirkət 0,5%)": "custom_unemployment_insurance_amount", +} + # Контекст для безопасного eval формул Salary Component. Зеркалит whitelisted_globals из HRMS. FORMULA_GLOBALS = { "int": int, @@ -170,8 +182,10 @@ def execute(filters=None): # формул baseline = 0 (no-op), для Gəlir vergisi baseline = -6 из-за # порога 200 AZN в base-части. Без вычитания MK-колонка для GV давала # бы -3 вместо 3 (см. формулу `(base - 200) * 0.03 + LE * 0.03`). + rate = flt(ss.exchange_rate) if currency == company_currency else 1.0 eh_amount = flt(ss_earning_map.get(ss.name, {}).get(EH_COMPONENT, 0)) mk_amount = flt(ss_earning_map.get(ss.name, {}).get(MK_COMPONENT, 0)) + gross_rated = flt(ss.gross_pay) * rate for d in DEDUCTION_TYPES: slug = frappe.scrub(d) spec = ded_specs.get(d) @@ -179,15 +193,15 @@ def execute(filters=None): row[prefix + "ded_eh_" + slug] += eval_deduction(spec, eh_amount, 0, ss) row[prefix + "ded_mk_" + slug] += eval_deduction(spec, 0, mk_amount, ss) - baseline - if currency == company_currency: - rate = flt(ss.exchange_rate) - row[prefix + "gross_pay"] += flt(ss.gross_pay) * rate - row[prefix + "total_deduction"] += flt(ss.total_deduction) * rate - row[prefix + "net_pay"] += flt(ss.net_pay) * rate - else: - row[prefix + "gross_pay"] += flt(ss.gross_pay) - row[prefix + "total_deduction"] += flt(ss.total_deduction) - row[prefix + "net_pay"] += flt(ss.net_pay) + # Contribution recomputed on gross net of its own "cəlb olunmayan" amount. + exempt_field = CONTRIBUTION_EXEMPT_FIELD.get(d) + if exempt_field: + base_net = max(gross_rated - flt(ss.get(exempt_field) or 0) * rate, 0.0) + row[prefix + "ded_cg_" + slug] += eval_deduction(spec, base_net, 0, ss) - baseline + + row[prefix + "gross_pay"] += gross_rated + row[prefix + "total_deduction"] += flt(ss.total_deduction) * rate + row[prefix + "net_pay"] += flt(ss.net_pay) * rate for indicator_field, amount_field, _label in TAX_FREE_FIELDS: row[prefix + indicator_field] = ss.get(indicator_field) @@ -228,6 +242,8 @@ def build_empty_row(ss, doj_map, currency, company_currency): row[prefix + slug] = 0.0 row[prefix + "ded_eh_" + slug] = 0.0 row[prefix + "ded_mk_" + slug] = 0.0 + if d in CONTRIBUTION_EXEMPT_FIELD: + row[prefix + "ded_cg_" + slug] = 0.0 for indicator_field, amount_field, _lbl in TAX_FREE_FIELDS: row[prefix + indicator_field] = None row[prefix + amount_field] = 0.0 @@ -365,6 +381,16 @@ def get_columns(): "width": 140, } ) + if deduction in CONTRIBUTION_EXEMPT_FIELD: + columns.append( + { + "label": deduction + " (cəlb edilən gəlirdən)" + suffix, + "fieldname": prefix + "ded_cg_" + frappe.scrub(deduction), + "fieldtype": "Currency", + "options": "currency", + "width": 200, + } + ) for deduction in DEDUCTION_TYPES: columns.append( {