fixed vat issue
This commit is contained in:
parent
22d22f4529
commit
b7758589a9
|
|
@ -7,45 +7,71 @@ from frappe.utils import flt
|
|||
from erpnext.selling.doctype.sales_order.sales_order import SalesOrder
|
||||
from erpnext.accounts.doctype.sales_invoice.sales_invoice import SalesInvoice
|
||||
|
||||
|
||||
def get_vat_template_type(tax_template):
|
||||
"""
|
||||
Определяет тип VAT шаблона, игнорируя суффикс компании
|
||||
Возвращает: '18%', 'daxil_18%', '0%', 'free', 'none'
|
||||
"""
|
||||
if not tax_template:
|
||||
return 'none'
|
||||
|
||||
# Убираем пробелы и проверяем начало строки
|
||||
tax_template = str(tax_template).strip()
|
||||
|
||||
# Порядок важен! Проверяем сначала более специфичные шаблоны
|
||||
if tax_template.startswith("ƏDV daxil 18%"):
|
||||
return 'daxil_18%'
|
||||
elif tax_template.startswith("ƏDV 18%"):
|
||||
return '18%'
|
||||
elif tax_template.startswith("ƏDV 0%"):
|
||||
return '0%'
|
||||
elif tax_template.startswith("ƏDV-dən azadolma"):
|
||||
return 'free'
|
||||
else:
|
||||
return 'none'
|
||||
|
||||
class CustomSalesInvoice(SalesInvoice):
|
||||
def on_update_after_submit(self):
|
||||
super().on_update_after_submit()
|
||||
|
||||
|
||||
def calculate_taxes_and_totals(self):
|
||||
# Сначала стандартные расчеты ERPNext
|
||||
super().calculate_taxes_and_totals()
|
||||
# Потом наши VAT расчеты
|
||||
self.calculate_vat_fields()
|
||||
|
||||
|
||||
def calculate_vat_fields(self):
|
||||
"""Рассчитывает VAT поля для всех строк"""
|
||||
if not self.items:
|
||||
return
|
||||
|
||||
|
||||
for item in self.items:
|
||||
self.calculate_item_vat_fields(item)
|
||||
|
||||
|
||||
def calculate_item_vat_fields(self, item):
|
||||
"""Рассчитывает VAT поля для одной строки"""
|
||||
if not item.item_code or flt(item.amount) <= 0:
|
||||
self.clear_item_vat_fields(item)
|
||||
return
|
||||
|
||||
|
||||
# Очищаем все VAT поля перед новым расчетом
|
||||
self.clear_item_vat_fields(item)
|
||||
|
||||
|
||||
# Блокируем tax_article если не разрешено
|
||||
self.handle_tax_article_permission(item)
|
||||
|
||||
|
||||
# Рассчитываем поля в зависимости от налогового шаблона
|
||||
amount = flt(item.amount)
|
||||
tax_template = item.item_tax_template
|
||||
|
||||
if tax_template == "ƏDV 18%":
|
||||
vat_type = get_vat_template_type(item.item_tax_template)
|
||||
|
||||
if vat_type == '18%':
|
||||
self.calculate_18_percent_vat(item, amount)
|
||||
elif tax_template == "ƏDV 0%":
|
||||
elif vat_type == 'daxil_18%':
|
||||
self.calculate_18_percent_vat_inclusive(item, amount)
|
||||
elif vat_type == '0%':
|
||||
self.calculate_0_percent_vat(item, amount)
|
||||
elif tax_template == "ƏDV-dən azadolma":
|
||||
elif vat_type == 'free':
|
||||
self.calculate_vat_free(item, amount)
|
||||
else:
|
||||
self.calculate_without_vat(item, amount)
|
||||
|
|
@ -66,21 +92,30 @@ class CustomSalesInvoice(SalesInvoice):
|
|||
|
||||
def handle_tax_article_permission(self, item):
|
||||
"""Обрабатывает разрешения для поля tax_article"""
|
||||
tax_template = item.item_tax_template
|
||||
is_allowed = tax_template in ["ƏDV 0%", "ƏDV-dən azadolma"]
|
||||
|
||||
vat_type = get_vat_template_type(item.item_tax_template)
|
||||
is_allowed = vat_type in ['0%', 'free']
|
||||
|
||||
# Очищаем tax_article если оно не должно быть доступно
|
||||
if not is_allowed and item.tax_article:
|
||||
item.tax_article = None
|
||||
|
||||
def calculate_18_percent_vat(self, item, amount):
|
||||
"""Рассчитывает поля для ƏDV 18%"""
|
||||
"""Рассчитывает поля для ƏDV 18% (НДС сверху)"""
|
||||
vat_18_total = amount * 1.18
|
||||
vat_amount = vat_18_total - amount
|
||||
|
||||
|
||||
item.vat_18_percent_with_amount = vat_18_total
|
||||
item.vat_amount = vat_amount
|
||||
|
||||
|
||||
def calculate_18_percent_vat_inclusive(self, item, amount):
|
||||
"""Рассчитывает поля для ƏDV daxil 18% (НДС в том числе)"""
|
||||
# amount уже включает НДС, выделяем его
|
||||
amount_without_vat = amount / 1.18
|
||||
vat_amount = amount - amount_without_vat
|
||||
|
||||
item.vat_18_percent_with_amount = amount
|
||||
item.vat_amount = vat_amount
|
||||
|
||||
def calculate_0_percent_vat(self, item, amount):
|
||||
"""Рассчитывает поля для ƏDV 0%"""
|
||||
item.vat_0_percent_with_amount = amount
|
||||
|
|
@ -97,42 +132,44 @@ class CustomSalesInvoice(SalesInvoice):
|
|||
class CustomSalesOrder(SalesOrder):
|
||||
def on_update_after_submit(self):
|
||||
super().on_update_after_submit()
|
||||
|
||||
|
||||
def calculate_taxes_and_totals(self):
|
||||
# Сначала стандартные расчеты ERPNext
|
||||
super().calculate_taxes_and_totals()
|
||||
# Потом наши VAT расчеты
|
||||
self.calculate_vat_fields()
|
||||
|
||||
|
||||
def calculate_vat_fields(self):
|
||||
"""Рассчитывает VAT поля для всех строк"""
|
||||
if not self.items:
|
||||
return
|
||||
|
||||
|
||||
for item in self.items:
|
||||
self.calculate_item_vat_fields(item)
|
||||
|
||||
|
||||
def calculate_item_vat_fields(self, item):
|
||||
"""Рассчитывает VAT поля для одной строки"""
|
||||
if not item.item_code or flt(item.amount) <= 0:
|
||||
self.clear_item_vat_fields(item)
|
||||
return
|
||||
|
||||
|
||||
# Очищаем все VAT поля перед новым расчетом
|
||||
self.clear_item_vat_fields(item)
|
||||
|
||||
|
||||
# Блокируем tax_article если не разрешено
|
||||
self.handle_tax_article_permission(item)
|
||||
|
||||
|
||||
# Рассчитываем поля в зависимости от налогового шаблона
|
||||
amount = flt(item.amount)
|
||||
tax_template = item.item_tax_template
|
||||
|
||||
if tax_template == "ƏDV 18%":
|
||||
vat_type = get_vat_template_type(item.item_tax_template)
|
||||
|
||||
if vat_type == '18%':
|
||||
self.calculate_18_percent_vat(item, amount)
|
||||
elif tax_template == "ƏDV 0%":
|
||||
elif vat_type == 'daxil_18%':
|
||||
self.calculate_18_percent_vat_inclusive(item, amount)
|
||||
elif vat_type == '0%':
|
||||
self.calculate_0_percent_vat(item, amount)
|
||||
elif tax_template == "ƏDV-dən azadolma":
|
||||
elif vat_type == 'free':
|
||||
self.calculate_vat_free(item, amount)
|
||||
else:
|
||||
self.calculate_without_vat(item, amount)
|
||||
|
|
@ -153,21 +190,30 @@ class CustomSalesOrder(SalesOrder):
|
|||
|
||||
def handle_tax_article_permission(self, item):
|
||||
"""Обрабатывает разрешения для поля tax_article"""
|
||||
tax_template = item.item_tax_template
|
||||
is_allowed = tax_template in ["ƏDV 0%", "ƏDV-dən azadolma"]
|
||||
|
||||
vat_type = get_vat_template_type(item.item_tax_template)
|
||||
is_allowed = vat_type in ['0%', 'free']
|
||||
|
||||
# Очищаем tax_article если оно не должно быть доступно
|
||||
if not is_allowed and item.tax_article:
|
||||
item.tax_article = None
|
||||
|
||||
def calculate_18_percent_vat(self, item, amount):
|
||||
"""Рассчитывает поля для ƏDV 18%"""
|
||||
"""Рассчитывает поля для ƏDV 18% (НДС сверху)"""
|
||||
vat_18_total = amount * 1.18
|
||||
vat_amount = vat_18_total - amount
|
||||
|
||||
|
||||
item.vat_18_percent_with_amount = vat_18_total
|
||||
item.vat_amount = vat_amount
|
||||
|
||||
|
||||
def calculate_18_percent_vat_inclusive(self, item, amount):
|
||||
"""Рассчитывает поля для ƏDV daxil 18% (НДС в том числе)"""
|
||||
# amount уже включает НДС, выделяем его
|
||||
amount_without_vat = amount / 1.18
|
||||
vat_amount = amount - amount_without_vat
|
||||
|
||||
item.vat_18_percent_with_amount = amount
|
||||
item.vat_amount = vat_amount
|
||||
|
||||
def calculate_0_percent_vat(self, item, amount):
|
||||
"""Рассчитывает поля для ƏDV 0%"""
|
||||
item.vat_0_percent_with_amount = amount
|
||||
|
|
@ -208,27 +254,29 @@ def calculate_vat_fields_for_doc(doc):
|
|||
"""Универсальная функция для расчета VAT полей"""
|
||||
if not doc.items:
|
||||
return
|
||||
|
||||
|
||||
for item in doc.items:
|
||||
if not item.item_code or flt(item.amount) <= 0:
|
||||
clear_vat_fields(item)
|
||||
continue
|
||||
|
||||
|
||||
# Очищаем все VAT поля перед новым расчетом
|
||||
clear_vat_fields(item)
|
||||
|
||||
|
||||
# Блокируем tax_article если не разрешено
|
||||
handle_tax_article_permission(item)
|
||||
|
||||
|
||||
# Рассчитываем поля в зависимости от налогового шаблона
|
||||
amount = flt(item.amount)
|
||||
tax_template = item.item_tax_template
|
||||
|
||||
if tax_template == "ƏDV 18%":
|
||||
vat_type = get_vat_template_type(item.item_tax_template)
|
||||
|
||||
if vat_type == '18%':
|
||||
calculate_18_percent_vat(item, amount)
|
||||
elif tax_template == "ƏDV 0%":
|
||||
elif vat_type == 'daxil_18%':
|
||||
calculate_18_percent_vat_inclusive(item, amount)
|
||||
elif vat_type == '0%':
|
||||
calculate_0_percent_vat(item, amount)
|
||||
elif tax_template == "ƏDV-dən azadolma":
|
||||
elif vat_type == 'free':
|
||||
calculate_vat_free(item, amount)
|
||||
else:
|
||||
calculate_without_vat(item, amount)
|
||||
|
|
@ -251,22 +299,32 @@ def clear_vat_fields(item):
|
|||
|
||||
def handle_tax_article_permission(item):
|
||||
"""Обрабатывает разрешения для поля tax_article"""
|
||||
tax_template = item.item_tax_template
|
||||
is_allowed = tax_template in ["ƏDV 0%", "ƏDV-dən azadolma"]
|
||||
|
||||
vat_type = get_vat_template_type(item.item_tax_template)
|
||||
is_allowed = vat_type in ['0%', 'free']
|
||||
|
||||
if not is_allowed and item.tax_article:
|
||||
item.tax_article = None
|
||||
|
||||
|
||||
def calculate_18_percent_vat(item, amount):
|
||||
"""Рассчитывает поля для ƏDV 18%"""
|
||||
"""Рассчитывает поля для ƏDV 18% (НДС сверху)"""
|
||||
vat_18_total = amount * 1.18
|
||||
vat_amount = vat_18_total - amount
|
||||
|
||||
|
||||
item.vat_18_percent_with_amount = vat_18_total
|
||||
item.vat_amount = vat_amount
|
||||
|
||||
|
||||
def calculate_18_percent_vat_inclusive(item, amount):
|
||||
"""Рассчитывает поля для ƏDV daxil 18% (НДС в том числе)"""
|
||||
# amount уже включает НДС, выделяем его
|
||||
amount_without_vat = amount / 1.18
|
||||
vat_amount = amount - amount_without_vat
|
||||
|
||||
item.vat_18_percent_with_amount = amount
|
||||
item.vat_amount = vat_amount
|
||||
|
||||
|
||||
def calculate_0_percent_vat(item, amount):
|
||||
"""Рассчитывает поля для ƏDV 0%"""
|
||||
item.vat_0_percent_with_amount = amount
|
||||
|
|
|
|||
|
|
@ -182,22 +182,26 @@ jey_erp.vat_calculator = {
|
|||
// ОБНОВЛЕНО: tax_article разрешен только для ƏDV 0% и ƏDV-dən azadolma
|
||||
// Для обоих типов НДС 18% поле заблокировано
|
||||
is_tax_article_allowed: function(tax_template) {
|
||||
return tax_template === "ƏDV 0%" || tax_template === "ƏDV-dən azadolma";
|
||||
if (!tax_template) return false;
|
||||
const template = tax_template.trim();
|
||||
return template.startsWith("ƏDV 0%") || template.startsWith("ƏDV-dən azadolma");
|
||||
},
|
||||
|
||||
// НОВАЯ функция: возвращает фильтр для tax_article в зависимости от налогового шаблона
|
||||
get_tax_article_filter: function(tax_template) {
|
||||
switch (tax_template) {
|
||||
case "ƏDV 0%":
|
||||
return {
|
||||
"parent_tax_article": "ƏDV-yə 0% dərəcə ilə tutulan əməliyyatlar"
|
||||
};
|
||||
case "ƏDV-dən azadolma":
|
||||
return {
|
||||
"parent_tax_article": "ƏDV-dən azad olunan əməliyyatlar"
|
||||
};
|
||||
default:
|
||||
return null;
|
||||
if (!tax_template) return null;
|
||||
const template = tax_template.trim();
|
||||
|
||||
if (template.startsWith("ƏDV 0%")) {
|
||||
return {
|
||||
"parent_tax_article": "ƏDV-yə 0% dərəcə ilə tutulan əməliyyatlar"
|
||||
};
|
||||
} else if (template.startsWith("ƏDV-dən azadolma")) {
|
||||
return {
|
||||
"parent_tax_article": "ƏDV-dən azad olunan əməliyyatlar"
|
||||
};
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -272,7 +276,7 @@ jey_erp.vat_calculator = {
|
|||
|
||||
calculate_vat_fields: function(cdt, cdn, frm = null) {
|
||||
const item = locals[cdt][cdn];
|
||||
|
||||
|
||||
// Получаем актуальные значения
|
||||
let amount;
|
||||
if (frm) {
|
||||
|
|
@ -290,41 +294,32 @@ jey_erp.vat_calculator = {
|
|||
|
||||
if (amount <= 0) return;
|
||||
|
||||
const tax_template = item.item_tax_template;
|
||||
|
||||
switch (tax_template) {
|
||||
case "ƏDV 18%":
|
||||
// НДС 18% СВЕРХУ: к amount добавляется 18%
|
||||
// amount = 100 -> vat_amount = 18, total = 118
|
||||
const vat_amount_top = amount * 0.18;
|
||||
const total_with_vat_top = amount + vat_amount_top;
|
||||
|
||||
frappe.model.set_value(cdt, cdn, 'vat_18_percent_with_amount', total_with_vat_top);
|
||||
frappe.model.set_value(cdt, cdn, 'vat_amount', vat_amount_top);
|
||||
break;
|
||||
|
||||
case "ƏDV daxil 18%":
|
||||
// НДС 18% В ТОМ ЧИСЛЕ: из amount выделяется НДС
|
||||
// amount = 100 -> vat_amount = 15.25, amount без НДС = 84.75, total = 100
|
||||
const total_with_vat_included = amount;
|
||||
const amount_without_vat = total_with_vat_included / 1.18;
|
||||
const vat_amount_included = total_with_vat_included - amount_without_vat;
|
||||
|
||||
frappe.model.set_value(cdt, cdn, 'vat_18_percent_with_amount', total_with_vat_included);
|
||||
frappe.model.set_value(cdt, cdn, 'vat_amount', vat_amount_included);
|
||||
break;
|
||||
|
||||
case "ƏDV 0%":
|
||||
frappe.model.set_value(cdt, cdn, 'vat_0_percent_with_amount', amount);
|
||||
break;
|
||||
|
||||
case "ƏDV-dən azadolma":
|
||||
frappe.model.set_value(cdt, cdn, 'vat_free_amount', amount);
|
||||
break;
|
||||
|
||||
default:
|
||||
frappe.model.set_value(cdt, cdn, 'amount_without_vat', amount);
|
||||
break;
|
||||
const tax_template = (item.item_tax_template || '').trim();
|
||||
|
||||
// Используем startsWith вместо точного сравнения
|
||||
if (tax_template.startsWith("ƏDV daxil 18%")) {
|
||||
// НДС 18% В ТОМ ЧИСЛЕ: из amount выделяется НДС
|
||||
// amount = 100 -> vat_amount = 15.25, amount без НДС = 84.75, total = 100
|
||||
const total_with_vat_included = amount;
|
||||
const amount_without_vat = total_with_vat_included / 1.18;
|
||||
const vat_amount_included = total_with_vat_included - amount_without_vat;
|
||||
|
||||
frappe.model.set_value(cdt, cdn, 'vat_18_percent_with_amount', total_with_vat_included);
|
||||
frappe.model.set_value(cdt, cdn, 'vat_amount', vat_amount_included);
|
||||
} else if (tax_template.startsWith("ƏDV 18%")) {
|
||||
// НДС 18% СВЕРХУ: к amount добавляется 18%
|
||||
// amount = 100 -> vat_amount = 18, total = 118
|
||||
const vat_amount_top = amount * 0.18;
|
||||
const total_with_vat_top = amount + vat_amount_top;
|
||||
|
||||
frappe.model.set_value(cdt, cdn, 'vat_18_percent_with_amount', total_with_vat_top);
|
||||
frappe.model.set_value(cdt, cdn, 'vat_amount', vat_amount_top);
|
||||
} else if (tax_template.startsWith("ƏDV 0%")) {
|
||||
frappe.model.set_value(cdt, cdn, 'vat_0_percent_with_amount', amount);
|
||||
} else if (tax_template.startsWith("ƏDV-dən azadolma")) {
|
||||
frappe.model.set_value(cdt, cdn, 'vat_free_amount', amount);
|
||||
} else {
|
||||
frappe.model.set_value(cdt, cdn, 'amount_without_vat', amount);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue