302 lines
12 KiB
Python
302 lines
12 KiB
Python
import frappe
|
||
import json
|
||
import os
|
||
|
||
@frappe.whitelist()
|
||
def get_tax_exempt_articles(doctype, txt, searchfield, start, page_len, filters):
|
||
"""Возвращает список налоговых статей для tax exempt assets"""
|
||
|
||
# Ключевые части названий для поиска
|
||
allowed_patterns = [
|
||
'199.1',
|
||
'199.4.1',
|
||
'199.4.2',
|
||
'199.4.3',
|
||
'199.4.4',
|
||
'199.5',
|
||
'199.7',
|
||
'199.8',
|
||
'199.9',
|
||
'199.11',
|
||
'199.14',
|
||
'199.15',
|
||
'199.16',
|
||
'199.17',
|
||
'199.18',
|
||
'199.19',
|
||
'199.20',
|
||
'227.1',
|
||
'Qanunla təsdiq olunmuş hasilatın pay bölgüsü',
|
||
'Xüsusi iqtisadi zonalar',
|
||
'Azərbaycan Respublikasının tərəfdar çıxdığı beynəlxalq müqavilələr'
|
||
]
|
||
|
||
# Строим условие для поиска
|
||
conditions = []
|
||
for pattern in allowed_patterns:
|
||
conditions.append(f"name LIKE '%{pattern}%'")
|
||
|
||
# Добавляем поисковый текст если есть
|
||
where_clause = f"({' OR '.join(conditions)})"
|
||
if txt:
|
||
where_clause += f" AND name LIKE '%{txt}%'"
|
||
|
||
# Выполняем запрос
|
||
result = frappe.db.sql(f"""
|
||
SELECT name
|
||
FROM `tabTax Article`
|
||
WHERE {where_clause}
|
||
ORDER BY name
|
||
LIMIT {start}, {page_len}
|
||
""")
|
||
|
||
return result
|
||
|
||
@frappe.whitelist()
|
||
def get_land_tax_articles(doctype, txt, searchfield, start, page_len, filters):
|
||
"""Возвращает список налоговых статей для земельных участков"""
|
||
|
||
# Ключевые части названий для поиска земельных участков
|
||
allowed_patterns = [
|
||
'Vergi Məcəlləsinin 207.3-cü maddəsinə əsasən',
|
||
'Vergi Məcəlləsinin 207.4-cü maddəsinə əsasən',
|
||
'Vergi Məcəlləsinin 207.5-ci maddəsinə əsasən',
|
||
'Vergi Məcəlləsinin 207.6-cı maddəsinə əsasən',
|
||
'Vergi Məcəlləsinin 207.7-ci maddəsinə əsasən',
|
||
'Vergi Məcəlləsinin 207.8-ci maddəsinə əsasən',
|
||
'Vergi Məcəlləsinin 207.9-cu maddəsinə əsasən',
|
||
'Vergi Məcəlləsinin 207.10-cu maddəsinə əsasən',
|
||
'Vergi Məcəlləsinin 207.11-ci maddəsinə əsasən',
|
||
'Vergi məcəlləsinin 207.12-ci maddəsinə əsasən',
|
||
'Vergi Məcəlləsinin 227.1-ci maddəsinə əsasən'
|
||
]
|
||
|
||
# Строим условие для поиска
|
||
conditions = []
|
||
for pattern in allowed_patterns:
|
||
conditions.append(f"name LIKE '%{pattern}%'")
|
||
|
||
# Добавляем поисковый текст если есть
|
||
where_clause = f"({' OR '.join(conditions)})"
|
||
if txt:
|
||
where_clause += f" AND name LIKE '%{txt}%'"
|
||
|
||
# Выполняем запрос
|
||
result = frappe.db.sql(f"""
|
||
SELECT name
|
||
FROM `tabTax Article`
|
||
WHERE {where_clause}
|
||
ORDER BY name
|
||
LIMIT {start}, {page_len}
|
||
""")
|
||
|
||
return result
|
||
|
||
# ===============================
|
||
# СЕЛЬСКОХОЗЯЙСТВЕННЫЕ ЗЕМЛИ
|
||
# ===============================
|
||
|
||
@frappe.whitelist()
|
||
def calculate_gross_purchase_amount(hectare, cadastral_district_name, quality_groups, agricultural_land_purpose):
|
||
"""
|
||
Рассчитывает Gross Purchase Amount для сельскохозяйственных земель
|
||
Формула: hectare × балл × наценка
|
||
"""
|
||
try:
|
||
# Валидация входных данных
|
||
if not hectare or not cadastral_district_name or not quality_groups or not agricultural_land_purpose:
|
||
frappe.throw("Не все поля заполнены для расчета")
|
||
|
||
# Получаем балл из JSON файла
|
||
score = get_cadastral_score(cadastral_district_name, quality_groups)
|
||
|
||
# Определяем наценку
|
||
markup = get_markup_coefficient(agricultural_land_purpose)
|
||
|
||
# Расчет по формуле
|
||
result = float(hectare) * score * markup
|
||
|
||
return {
|
||
'gross_purchase_amount': result,
|
||
'calculation_details': {
|
||
'hectare': float(hectare),
|
||
'score': score,
|
||
'markup': markup,
|
||
'formula': f"{hectare} × {score} × {markup} = {result}"
|
||
}
|
||
}
|
||
|
||
except Exception as e:
|
||
frappe.throw(f"Ошибка при расчете: {str(e)}")
|
||
|
||
def get_cadastral_score(cadastral_district_name, quality_group):
|
||
"""
|
||
Извлекает балл из JSON файла на основе названия кадастрового района и группы качества
|
||
"""
|
||
try:
|
||
# Путь к JSON файлу
|
||
json_file_path = frappe.get_app_path('jey_erp', 'data', 'cadastral_points_data.json')
|
||
|
||
# Читаем JSON файл
|
||
with open(json_file_path, 'r', encoding='utf-8') as file:
|
||
data = json.load(file)
|
||
|
||
# Поиск соответствующего региона
|
||
for region in data.get('cadastral_regions', []):
|
||
if region.get('region_name') == cadastral_district_name:
|
||
# Получаем балл для указанной группы качества
|
||
quality_groups = region.get('quality_groups', {})
|
||
score = quality_groups.get(quality_group)
|
||
|
||
# Если балл null или не найден, возвращаем 0
|
||
return score if score is not None else 0
|
||
|
||
# Если регион не найден
|
||
frappe.throw(f"Кадастровый район '{cadastral_district_name}' не найден в базе данных")
|
||
|
||
except FileNotFoundError:
|
||
frappe.throw("Файл с кадастровыми данными не найден. Обратитесь к администратору системы")
|
||
except json.JSONDecodeError:
|
||
frappe.throw("Ошибка чтения файла с кадастровыми данными")
|
||
except Exception as e:
|
||
frappe.throw(f"Ошибка при получении кадастрового балла: {str(e)}")
|
||
|
||
def get_markup_coefficient(agricultural_land_purpose):
|
||
"""
|
||
Определяет коэффициент наценки на основе цели использования земли
|
||
"""
|
||
markup_map = {
|
||
"Əkin, dinc və çoxillik əkmələr": 0.06,
|
||
"Biçənək, örüş və otlaqlar": 0.006 # 0.06 / 10
|
||
}
|
||
|
||
coefficient = markup_map.get(agricultural_land_purpose)
|
||
|
||
if coefficient is None:
|
||
frappe.throw(f"Неизвестный тип назначения земли: {agricultural_land_purpose}")
|
||
|
||
return coefficient
|
||
|
||
# ===============================
|
||
# ПРОМЫШЛЕННЫЕ/КОММЕРЧЕСКИЕ ЗЕМЛИ
|
||
# ===============================
|
||
|
||
@frappe.whitelist()
|
||
def calculate_industrial_gross_purchase_amount(hectare, territorial_unit_name, industrial_land_purpose):
|
||
"""
|
||
Рассчитывает Gross Purchase Amount для промышленных земель
|
||
Формула: (площадь_в_м² ÷ 100) × балл (прогрессивная система)
|
||
"""
|
||
try:
|
||
# Валидация входных данных
|
||
if not hectare or not territorial_unit_name or not industrial_land_purpose:
|
||
frappe.throw("Не все поля заполнены для расчета")
|
||
|
||
# Используем значение как есть - это квадратные метры
|
||
area_sqm = float(hectare)
|
||
|
||
# Получаем баллы из JSON файла
|
||
score_data = get_industrial_land_scores(territorial_unit_name, industrial_land_purpose)
|
||
|
||
# Рассчитываем по прогрессивной формуле
|
||
calculation_result = calculate_industrial_land_formula(area_sqm, score_data)
|
||
|
||
return {
|
||
'gross_purchase_amount': calculation_result['total'],
|
||
'calculation_details': calculation_result
|
||
}
|
||
|
||
except Exception as e:
|
||
frappe.throw(f"Ошибка при расчете: {str(e)}")
|
||
|
||
def get_industrial_land_scores(territorial_unit_name, industrial_land_purpose):
|
||
"""
|
||
Извлекает баллы из JSON файла для промышленных земель
|
||
"""
|
||
try:
|
||
# Путь к JSON файлу
|
||
json_file_path = frappe.get_app_path('jey_erp', 'data', 'industrial_land_data.json')
|
||
|
||
# Читаем JSON файл
|
||
with open(json_file_path, 'r', encoding='utf-8') as file:
|
||
data = json.load(file)
|
||
|
||
# Поиск соответствующего региона
|
||
for region in data.get('industrial_land_regions', []):
|
||
if region.get('settlement_name') == territorial_unit_name:
|
||
# Получаем баллы для указанного назначения земли
|
||
land_purpose_rates = region.get('land_purpose_rates', {})
|
||
purpose_rates = land_purpose_rates.get(industrial_land_purpose)
|
||
|
||
if purpose_rates:
|
||
return {
|
||
'up_to_10000': purpose_rates.get('up_to_10000_sqm', 0),
|
||
'above_10000': purpose_rates.get('above_10000_sqm', 0)
|
||
}
|
||
|
||
# Если регион или назначение не найдено
|
||
frappe.throw(f"Не найдены данные для территории '{territorial_unit_name}' и назначения '{industrial_land_purpose}'")
|
||
|
||
except FileNotFoundError:
|
||
frappe.throw("Файл с данными промышленных земель не найден. Обратитесь к администратору системы")
|
||
except json.JSONDecodeError:
|
||
frappe.throw("Ошибка чтения файла с данными промышленных земель")
|
||
except Exception as e:
|
||
frappe.throw(f"Ошибка при получении баллов промышленной земли: {str(e)}")
|
||
|
||
def calculate_industrial_land_formula(area_sqm, score_data):
|
||
"""
|
||
Рассчитывает стоимость по прогрессивной формуле для промышленных земель
|
||
"""
|
||
up_to_10000_score = score_data['up_to_10000']
|
||
above_10000_score = score_data['above_10000']
|
||
|
||
calculation_parts = []
|
||
total = 0
|
||
|
||
if area_sqm <= 10000:
|
||
# Вся площадь до 10000 м²
|
||
part_result = (area_sqm / 100) * up_to_10000_score
|
||
total = part_result
|
||
|
||
calculation_parts.append({
|
||
'area': area_sqm,
|
||
'score': up_to_10000_score,
|
||
'formula': f"{area_sqm} ÷ 100 × {up_to_10000_score} = {part_result}",
|
||
'result': part_result
|
||
})
|
||
|
||
formula_text = f"{area_sqm} ÷ 100 × {up_to_10000_score} = {total}"
|
||
|
||
else:
|
||
# Прогрессивная система: до 10000 м² + свыше 10000 м²
|
||
|
||
# Первые 10000 м²
|
||
part1_result = (10000 / 100) * up_to_10000_score
|
||
calculation_parts.append({
|
||
'area': 10000,
|
||
'score': up_to_10000_score,
|
||
'formula': f"10000 ÷ 100 × {up_to_10000_score} = {part1_result}",
|
||
'result': part1_result
|
||
})
|
||
|
||
# Оставшаяся площадь свыше 10000 м²
|
||
remaining_area = area_sqm - 10000
|
||
part2_result = (remaining_area / 100) * above_10000_score
|
||
calculation_parts.append({
|
||
'area': remaining_area,
|
||
'score': above_10000_score,
|
||
'formula': f"{remaining_area} ÷ 100 × {above_10000_score} = {part2_result}",
|
||
'result': part2_result
|
||
})
|
||
|
||
total = part1_result + part2_result
|
||
formula_text = f"(10000 ÷ 100 × {up_to_10000_score}) + ({remaining_area} ÷ 100 × {above_10000_score}) = {part1_result} + {part2_result} = {total}"
|
||
|
||
return {
|
||
'total': total,
|
||
'area_sqm': area_sqm,
|
||
'formula': formula_text,
|
||
'calculation_parts': calculation_parts,
|
||
'scores_used': score_data
|
||
} |