From fd54a5e9f226d1dc2056d48e5d513fb6fc91b794 Mon Sep 17 00:00:00 2001 From: Ali <010109ali@gmail.com> Date: Fri, 28 Nov 2025 16:20:49 +0400 Subject: [PATCH] tax exempt now in formula for land tax decl --- .../land_tax_declaration.js | 27 +++----- .../land_tax_declaration.py | 68 +++++++++++++++---- 2 files changed, 64 insertions(+), 31 deletions(-) diff --git a/taxes_az/taxes_az/doctype/land_tax_declaration/land_tax_declaration.js b/taxes_az/taxes_az/doctype/land_tax_declaration/land_tax_declaration.js index 91f1e78..f9ae299 100644 --- a/taxes_az/taxes_az/doctype/land_tax_declaration/land_tax_declaration.js +++ b/taxes_az/taxes_az/doctype/land_tax_declaration/land_tax_declaration.js @@ -145,20 +145,22 @@ function get_unique_purposes(assets) { function group_and_create_agricultural_rows_silent(frm, table_fieldname, assets, agricultural_purposes, resolve) { let grouped_assets = {}; - + assets.forEach(function(asset) { let group_key = create_agricultural_group_key(asset, agricultural_purposes); - + if (!grouped_assets[group_key]) { grouped_assets[group_key] = { asset: asset, total_area: 0, + total_tax_exempt_area: 0, count: 0, asset_names: [] }; } - + grouped_assets[group_key].total_area += (asset.area || 0); + grouped_assets[group_key].total_tax_exempt_area += (asset.tax_exempt_area || 0); grouped_assets[group_key].count += 1; grouped_assets[group_key].asset_names.push(asset.name); }); @@ -262,7 +264,8 @@ function calculate_agricultural_tax_for_row_silent(row, asset, total_area, group cadastral_district_name: asset.cadastral_district_name, quality_groups: asset.quality_groups, agricultural_land_purpose: asset.agricultural_land_purpose, - agricultural_purpose_name: agricultural_purpose_name + agricultural_purpose_name: agricultural_purpose_name, + tax_exempt_area: group_info.total_tax_exempt_area || 0 }, callback: function(response) { if (response.message && 'tax_amount' in response.message) { @@ -402,26 +405,18 @@ function fill_industrial_row_fields(row, asset, total_area, group_info) { } function calculate_industrial_tax_for_row_silent(row, asset, total_area, group_info, callback) { - let tax_exempt_area = group_info.total_tax_exempt_area || 0; - let taxable_area = total_area - tax_exempt_area; - - if (taxable_area <= 0) { - row.vergiməbləğimanatla = 0; - callback(); - return; - } - if (!asset.territorial_unit_name || !asset.industrial_land_purpose) { callback(); return; } - + frappe.call({ method: 'taxes_az.taxes_az.doctype.land_tax_declaration.land_tax_declaration.calculate_industrial_tax', args: { - area_sqm: taxable_area, + area_sqm: total_area, territorial_unit_name: asset.territorial_unit_name, - industrial_land_purpose: asset.industrial_land_purpose + industrial_land_purpose: asset.industrial_land_purpose, + tax_exempt_area: group_info.total_tax_exempt_area || 0 }, callback: function(response) { if (response.message && 'tax_amount' in response.message) { diff --git a/taxes_az/taxes_az/doctype/land_tax_declaration/land_tax_declaration.py b/taxes_az/taxes_az/doctype/land_tax_declaration/land_tax_declaration.py index 5c6d397..c31234a 100644 --- a/taxes_az/taxes_az/doctype/land_tax_declaration/land_tax_declaration.py +++ b/taxes_az/taxes_az/doctype/land_tax_declaration/land_tax_declaration.py @@ -59,17 +59,35 @@ def get_doctype_fields_info(): return {'error': str(e)} @frappe.whitelist() -def calculate_agricultural_tax(area_value, cadastral_district_name, quality_groups, agricultural_land_purpose, agricultural_purpose_name=None): +def calculate_agricultural_tax(area_value, cadastral_district_name, quality_groups, agricultural_land_purpose, agricultural_purpose_name=None, tax_exempt_area=None): try: if area_value is None: frappe.throw("Area value is required") - + area_float = float(area_value) - + + # Вычитаем освобожденную от налогов площадь + if tax_exempt_area: + try: + exempt_float = float(tax_exempt_area) + area_float = max(0, area_float - exempt_float) + except (ValueError, TypeError): + frappe.log_error(f"Invalid tax_exempt_area value: {tax_exempt_area}") + + # Если вся площадь освобождена, возвращаем 0 + if area_float <= 0: + return { + 'tax_amount': 0, + 'calculation_details': { + 'area_sqm': area_float, + 'formula': 'All area is tax-exempt' + } + } + # Для неиспользуемых земель: Area × 2% if agricultural_purpose_name == 'Təyinatı üzrə istifadə edilməyən kənd təsərrüfatı torpaqları üzrə hesablanmış vergi məbləği': result = area_float * 0.02 - + return { 'tax_amount': result, 'calculation_details': { @@ -78,16 +96,16 @@ def calculate_agricultural_tax(area_value, cadastral_district_name, quality_grou 'formula': f"{area_float} sq.m × 0.02 = {result}" } } - + # Для используемых земель: Hectare × Score × Markup if not cadastral_district_name or not quality_groups or not agricultural_land_purpose: frappe.throw("Not all fields are filled for calculation") - - hectare_value = float(area_value) + + hectare_value = area_float score = get_cadastral_score(cadastral_district_name, quality_groups) markup = get_markup_coefficient(agricultural_land_purpose) result = hectare_value * score * markup - + return { 'tax_amount': result, 'calculation_details': { @@ -97,7 +115,7 @@ def calculate_agricultural_tax(area_value, cadastral_district_name, quality_grou 'formula': f"{hectare_value} ha × {score} × {markup} = {result}" } } - + except Exception as e: frappe.throw(f"Calculation error: {str(e)}") @@ -137,20 +155,39 @@ def get_markup_coefficient(agricultural_land_purpose): return coefficient @frappe.whitelist() -def calculate_industrial_tax(area_sqm, territorial_unit_name, industrial_land_purpose): +def calculate_industrial_tax(area_sqm, territorial_unit_name, industrial_land_purpose, tax_exempt_area=None): try: if area_sqm is None or not territorial_unit_name or not industrial_land_purpose: frappe.throw("Not all fields are filled for calculation") - + area_sqm_float = float(area_sqm) + + # Вычитаем освобожденную от налогов площадь + if tax_exempt_area: + try: + exempt_float = float(tax_exempt_area) + area_sqm_float = max(0, area_sqm_float - exempt_float) + except (ValueError, TypeError): + frappe.log_error(f"Invalid tax_exempt_area value: {tax_exempt_area}") + + # Если вся площадь освобождена, возвращаем 0 + if area_sqm_float <= 0: + return { + 'tax_amount': 0, + 'calculation_details': { + 'area_sqm': area_sqm_float, + 'formula': 'All area is tax-exempt' + } + } + score_data = get_industrial_land_scores(territorial_unit_name, industrial_land_purpose) calculation_result = calculate_industrial_land_formula(area_sqm_float, score_data) - + return { 'tax_amount': calculation_result['total'], 'calculation_details': calculation_result } - + except Exception as e: frappe.throw(f"Calculation error: {str(e)}") @@ -242,14 +279,15 @@ def get_assets_for_year(asset_type, year): if asset_type == 'Kənd təsərrüfatı təyinatlı torpaq sahələri': fields = [ - 'name', - 'asset_name', + 'name', + 'asset_name', 'agricultural_purpose', 'cadastral_district_name', 'cadastral_district_code', 'quality_groups', 'agricultural_land_purpose', 'area', + 'tax_exempt_area', 'purchase_date' ] else: