fixed tax exempt report

This commit is contained in:
Ali 2025-12-04 16:47:18 +04:00
parent 2af0325808
commit 76c25a9d49
1 changed files with 107 additions and 177 deletions

View File

@ -147,9 +147,24 @@ def get_field_key(tax_article):
return "article_other" return "article_other"
def check_erpnext_version():
"""Проверяет версию ERPNext и определяет, какое поле использовать для стоимости актива"""
# Проверяем наличие колонки net_purchase_amount
columns = frappe.db.get_table_columns("Asset")
has_net_purchase_amount = "net_purchase_amount" in columns
has_capitalization = "Asset Capitalization" in frappe.get_all("DocType", pluck="name")
return {
"purchase_amount_field": "net_purchase_amount" if has_net_purchase_amount else "gross_purchase_amount",
"has_capitalization": has_capitalization
}
def get_assets_with_tax_exempt_articles(filters, tax_exempt_articles): def get_assets_with_tax_exempt_articles(filters, tax_exempt_articles):
"""Получает активы с tax exempt статьями исключая активы года создания компании""" """Получает активы с tax exempt статьями исключая активы года создания компании"""
version_info = check_erpnext_version()
conditions = [] conditions = []
values = [] values = []
@ -178,7 +193,8 @@ def get_assets_with_tax_exempt_articles(filters, tax_exempt_articles):
if conditions: if conditions:
where_clause = "WHERE " + " AND ".join(conditions) where_clause = "WHERE " + " AND ".join(conditions)
# Исключаем капитализированные активы (как в стандартном отчете) # Исключаем капитализированные активы только если есть поддержка
if version_info["has_capitalization"]:
exclude_capitalized = """ exclude_capitalized = """
AND NOT EXISTS( AND NOT EXISTS(
SELECT 1 FROM `tabAsset Capitalization Asset Item` acai SELECT 1 FROM `tabAsset Capitalization Asset Item` acai
@ -190,6 +206,9 @@ def get_assets_with_tax_exempt_articles(filters, tax_exempt_articles):
""" """
where_clause += exclude_capitalized where_clause += exclude_capitalized
values.append(filters.get("from_date")) values.append(filters.get("from_date"))
else:
# В старой версии просто исключаем активы где есть запись в Asset Capitalization Asset Item
where_clause += " AND NOT EXISTS(SELECT name FROM `tabAsset Capitalization Asset Item` WHERE asset = a.name)"
query = f""" query = f"""
SELECT SELECT
@ -215,15 +234,14 @@ def get_asset_balances_from_standard_report(filters, asset_names):
if not asset_names: if not asset_names:
return [] return []
version_info = check_erpnext_version()
# Получаем детали активов # Получаем детали активов
asset_details = get_asset_details_for_tax_exempt(filters, asset_names) asset_details = get_asset_details_for_tax_exempt(filters, asset_names, version_info)
# Получаем депреciацию активов # Получаем депрециацию активов
asset_depreciation = get_asset_depreciation_for_tax_exempt(filters, asset_names) asset_depreciation = get_asset_depreciation_for_tax_exempt(filters, asset_names)
# Получаем корректировки стоимости
asset_value_adjustments = get_asset_value_adjustments_for_tax_exempt(filters, asset_names)
# Объединяем данные # Объединяем данные
result = [] result = []
@ -236,26 +254,14 @@ def get_asset_balances_from_standard_report(filters, asset_names):
{} {}
) )
# Находим корректировки для актива
adjustments = asset_value_adjustments.get(asset_name, {
'adjustment_before_from_date': 0.0,
'adjustment_till_to_date': 0.0
})
# Рассчитываем значения по логике стандартного отчета # Рассчитываем значения по логике стандартного отчета
adjustment_before_from_date = flt(adjustments['adjustment_before_from_date']) value_as_on_from_date = flt(asset_detail.get('cost_as_on_from_date', 0))
adjustment_till_to_date = flt(adjustments['adjustment_till_to_date'])
adjustment_during_period = adjustment_till_to_date - adjustment_before_from_date
value_as_on_from_date = flt(asset_detail.get('value_as_on_from_date', 0)) + adjustment_before_from_date
value_as_on_to_date = ( value_as_on_to_date = (
value_as_on_from_date + value_as_on_from_date +
flt(asset_detail.get('value_of_new_purchase', 0)) - flt(asset_detail.get('cost_of_new_purchase', 0)) -
flt(asset_detail.get('value_of_sold_asset', 0)) - flt(asset_detail.get('cost_of_sold_asset', 0)) -
flt(asset_detail.get('value_of_scrapped_asset', 0)) - flt(asset_detail.get('cost_of_scrapped_asset', 0))
flt(asset_detail.get('value_of_capitalized_asset', 0)) +
adjustment_during_period
) )
accumulated_depreciation_as_on_from_date = flt(depreciation.get('accumulated_depreciation_as_on_from_date', 0)) accumulated_depreciation_as_on_from_date = flt(depreciation.get('accumulated_depreciation_as_on_from_date', 0))
@ -263,8 +269,7 @@ def get_asset_balances_from_standard_report(filters, asset_names):
accumulated_depreciation_as_on_to_date = ( accumulated_depreciation_as_on_to_date = (
accumulated_depreciation_as_on_from_date + accumulated_depreciation_as_on_from_date +
flt(depreciation.get('depreciation_amount_during_the_period', 0)) - flt(depreciation.get('depreciation_amount_during_the_period', 0)) -
flt(depreciation.get('depreciation_eliminated_during_the_period', 0)) - flt(depreciation.get('depreciation_eliminated_during_the_period', 0))
flt(depreciation.get('depreciation_eliminated_via_reversal', 0))
) )
net_asset_value_as_on_to_date = value_as_on_to_date - accumulated_depreciation_as_on_to_date net_asset_value_as_on_to_date = value_as_on_to_date - accumulated_depreciation_as_on_to_date
@ -278,63 +283,16 @@ def get_asset_balances_from_standard_report(filters, asset_names):
return result return result
def get_asset_details_for_tax_exempt(filters, asset_names): def get_asset_details_for_tax_exempt(filters, asset_names, version_info):
"""Получает детали активов (из стандартного отчета)""" """Получает детали активов (совместимо со старой и новой версией)"""
asset_placeholders = ", ".join(["%s"] * len(asset_names)) asset_placeholders = ", ".join(["%s"] * len(asset_names))
purchase_amount_field = version_info["purchase_amount_field"]
query = f""" # Базовый запрос без капитализации
SELECT a.name, capitalization_check = ""
ifnull(sum(case when a.purchase_date < %s then if version_info["has_capitalization"]:
case when ifnull(a.disposal_date, 0) = 0 or a.disposal_date >= %s then capitalization_check = """
a.net_purchase_amount
else
0
end
else
0
end), 0) as value_as_on_from_date,
ifnull(sum(case when a.purchase_date >= %s then
a.net_purchase_amount
else
0
end), 0) as value_of_new_purchase,
ifnull(sum(case when ifnull(a.disposal_date, 0) != 0
and a.disposal_date >= %s
and a.disposal_date <= %s then
case when a.status = "Sold" then
a.net_purchase_amount
else
0
end
else
0
end), 0) as value_of_sold_asset,
ifnull(sum(case when ifnull(a.disposal_date, 0) != 0
and a.disposal_date >= %s
and a.disposal_date <= %s then
case when a.status = "Scrapped" then
a.net_purchase_amount
else
0
end
else
0
end), 0) as value_of_scrapped_asset,
ifnull(sum(case when ifnull(a.disposal_date, 0) != 0
and a.disposal_date >= %s
and a.disposal_date <= %s then
case when a.status = "Capitalized" then
a.net_purchase_amount
else
0
end
else
0
end), 0) as value_of_capitalized_asset
from `tabAsset` a
where a.docstatus=1 and a.company=%s and a.purchase_date <= %s
and a.name IN ({asset_placeholders})
and not exists( and not exists(
select 1 from `tabAsset Capitalization Asset Item` acai select 1 from `tabAsset Capitalization Asset Item` acai
join `tabAsset Capitalization` ac on acai.parent=ac.name join `tabAsset Capitalization` ac on acai.parent=ac.name
@ -342,37 +300,81 @@ def get_asset_details_for_tax_exempt(filters, asset_names):
and ac.posting_date < %s and ac.posting_date < %s
and ac.docstatus=1 and ac.docstatus=1
) )
"""
query = f"""
SELECT a.name,
ifnull(sum(case when a.purchase_date < %s then
case when ifnull(a.disposal_date, 0) = 0 or a.disposal_date >= %s then
a.{purchase_amount_field}
else
0
end
else
0
end), 0) as cost_as_on_from_date,
ifnull(sum(case when a.purchase_date >= %s then
a.{purchase_amount_field}
else
0
end), 0) as cost_of_new_purchase,
ifnull(sum(case when ifnull(a.disposal_date, 0) != 0
and a.disposal_date >= %s
and a.disposal_date <= %s then
case when a.status = "Sold" then
a.{purchase_amount_field}
else
0
end
else
0
end), 0) as cost_of_sold_asset,
ifnull(sum(case when ifnull(a.disposal_date, 0) != 0
and a.disposal_date >= %s
and a.disposal_date <= %s then
case when a.status = "Scrapped" then
a.{purchase_amount_field}
else
0
end
else
0
end), 0) as cost_of_scrapped_asset
from `tabAsset` a
where a.docstatus=1 and a.company=%s and a.purchase_date <= %s
and a.name IN ({asset_placeholders})
{capitalization_check}
group by a.name group by a.name
""" """
values = [ values = [
filters.get("from_date"), # value_as_on_from_date condition 1 filters.get("from_date"), # cost_as_on_from_date condition 1
filters.get("from_date"), # value_as_on_from_date condition 2 filters.get("from_date"), # cost_as_on_from_date condition 2
filters.get("from_date"), # value_of_new_purchase filters.get("from_date"), # cost_of_new_purchase
filters.get("from_date"), # value_of_sold_asset condition 1 filters.get("from_date"), # cost_of_sold_asset condition 1
filters.get("to_date"), # value_of_sold_asset condition 2 filters.get("to_date"), # cost_of_sold_asset condition 2
filters.get("from_date"), # value_of_scrapped_asset condition 1 filters.get("from_date"), # cost_of_scrapped_asset condition 1
filters.get("to_date"), # value_of_scrapped_asset condition 2 filters.get("to_date"), # cost_of_scrapped_asset condition 2
filters.get("from_date"), # value_of_capitalized_asset condition 1
filters.get("to_date"), # value_of_capitalized_asset condition 2
filters.get("company"), # company filter filters.get("company"), # company filter
filters.get("to_date"), # purchase_date filter filters.get("to_date"), # purchase_date filter
*asset_names, # asset names for IN clause *asset_names, # asset names for IN clause
filters.get("from_date") # capitalization exclusion
] ]
# Добавляем значение для капитализации если нужно
if version_info["has_capitalization"]:
values.append(filters.get("from_date"))
return frappe.db.sql(query, values, as_dict=True) return frappe.db.sql(query, values, as_dict=True)
def get_asset_depreciation_for_tax_exempt(filters, asset_names): def get_asset_depreciation_for_tax_exempt(filters, asset_names):
"""Получает депреciацию активов (из стандартного отчета)""" """Получает депреciацию активов (совместимо со старой и новой версией)"""
asset_placeholders = ", ".join(["%s"] * len(asset_names)) asset_placeholders = ", ".join(["%s"] * len(asset_names))
query = f""" query = f"""
SELECT results.name as asset, SELECT results.name as asset,
sum(results.accumulated_depreciation_as_on_from_date) as accumulated_depreciation_as_on_from_date, sum(results.accumulated_depreciation_as_on_from_date) as accumulated_depreciation_as_on_from_date,
sum(results.depreciation_eliminated_via_reversal) as depreciation_eliminated_via_reversal,
sum(results.depreciation_eliminated_during_the_period) as depreciation_eliminated_during_the_period, sum(results.depreciation_eliminated_during_the_period) as depreciation_eliminated_during_the_period,
sum(results.depreciation_amount_during_the_period) as depreciation_amount_during_the_period sum(results.depreciation_amount_during_the_period) as depreciation_amount_during_the_period
from (SELECT a.name as name, from (SELECT a.name as name,
@ -381,11 +383,6 @@ def get_asset_depreciation_for_tax_exempt(filters, asset_names):
else else
0 0
end), 0) as accumulated_depreciation_as_on_from_date, end), 0) as accumulated_depreciation_as_on_from_date,
ifnull(sum(case when gle.posting_date <= %s and ifnull(a.disposal_date, 0) = 0 then
gle.credit
else
0
end), 0) as depreciation_eliminated_via_reversal,
ifnull(sum(case when ifnull(a.disposal_date, 0) != 0 and a.disposal_date >= %s ifnull(sum(case when ifnull(a.disposal_date, 0) != 0 and a.disposal_date >= %s
and a.disposal_date <= %s and gle.posting_date <= a.disposal_date then and a.disposal_date <= %s and gle.posting_date <= a.disposal_date then
gle.debit gle.debit
@ -409,18 +406,18 @@ def get_asset_depreciation_for_tax_exempt(filters, asset_names):
a.docstatus=1 a.docstatus=1
and a.company=%s and a.company=%s
and a.purchase_date <= %s and a.purchase_date <= %s
and gle.debit != 0
and gle.is_cancelled = 0 and gle.is_cancelled = 0
and gle.account = ifnull(aca.depreciation_expense_account, company.depreciation_expense_account) and gle.account = ifnull(aca.depreciation_expense_account, company.depreciation_expense_account)
and a.name IN ({asset_placeholders}) and a.name IN ({asset_placeholders})
group by a.name group by a.name
union union
SELECT a.name as name, SELECT a.name as name,
ifnull(sum(case when ifnull(a.disposal_date, 0) != 0 and a.disposal_date < %s then ifnull(sum(case when ifnull(a.disposal_date, 0) != 0 and (a.disposal_date < %s or a.disposal_date > %s) then
0 0
else else
a.opening_accumulated_depreciation a.opening_accumulated_depreciation
end), 0) as accumulated_depreciation_as_on_from_date, end), 0) as accumulated_depreciation_as_on_from_date,
0 as depreciation_as_on_from_date_credit,
ifnull(sum(case when a.disposal_date >= %s and a.disposal_date <= %s then ifnull(sum(case when a.disposal_date >= %s and a.disposal_date <= %s then
a.opening_accumulated_depreciation a.opening_accumulated_depreciation
else else
@ -437,7 +434,6 @@ def get_asset_depreciation_for_tax_exempt(filters, asset_names):
values = [ values = [
filters.get("from_date"), # accumulated_depreciation_as_on_from_date condition 1 filters.get("from_date"), # accumulated_depreciation_as_on_from_date condition 1
filters.get("from_date"), # accumulated_depreciation_as_on_from_date condition 2 filters.get("from_date"), # accumulated_depreciation_as_on_from_date condition 2
filters.get("to_date"), # depreciation_eliminated_via_reversal
filters.get("from_date"), # depreciation_eliminated_during_the_period condition 1 filters.get("from_date"), # depreciation_eliminated_during_the_period condition 1
filters.get("to_date"), # depreciation_eliminated_during_the_period condition 2 filters.get("to_date"), # depreciation_eliminated_during_the_period condition 2
filters.get("from_date"), # depreciation_amount_during_the_period condition 1 filters.get("from_date"), # depreciation_amount_during_the_period condition 1
@ -448,6 +444,7 @@ def get_asset_depreciation_for_tax_exempt(filters, asset_names):
filters.get("to_date"), # a.purchase_date filters.get("to_date"), # a.purchase_date
*asset_names, # asset names for IN clause (first union) *asset_names, # asset names for IN clause (first union)
filters.get("from_date"), # disposal_date condition (second union) filters.get("from_date"), # disposal_date condition (second union)
filters.get("to_date"), # disposal_date condition (second union)
filters.get("from_date"), # disposal_date condition (second union) filters.get("from_date"), # disposal_date condition (second union)
filters.get("to_date"), # disposal_date condition (second union) filters.get("to_date"), # disposal_date condition (second union)
filters.get("company"), # a.company (second union) filters.get("company"), # a.company (second union)
@ -458,73 +455,6 @@ def get_asset_depreciation_for_tax_exempt(filters, asset_names):
return frappe.db.sql(query, values, as_dict=True) return frappe.db.sql(query, values, as_dict=True)
def get_asset_value_adjustments_for_tax_exempt(filters, asset_names):
"""Получает корректировки стоимости активов (из стандартного отчета)"""
asset_placeholders = ", ".join(["%s"] * len(asset_names))
query = f"""
SELECT
a.name AS asset,
IFNULL(
SUM(
CASE
WHEN gle.posting_date < %s
AND (a.disposal_date IS NULL OR a.disposal_date >= %s)
THEN gle.debit - gle.credit
ELSE 0
END
),
0) AS value_adjustment_before_from_date,
IFNULL(
SUM(
CASE
WHEN gle.posting_date <= %s
AND (a.disposal_date IS NULL OR a.disposal_date >= %s)
THEN gle.debit - gle.credit
ELSE 0
END
),
0) AS value_adjustment_till_to_date
FROM `tabGL Entry` gle
JOIN `tabAsset` a ON gle.against_voucher = a.name
JOIN `tabAsset Category Account` aca
ON aca.parent = a.asset_category
AND aca.company_name = %s
WHERE gle.is_cancelled = 0
AND a.docstatus = 1
AND a.company = %s
AND a.purchase_date <= %s
AND gle.account = aca.fixed_asset_account
AND a.name IN ({asset_placeholders})
GROUP BY a.name
"""
values = [
filters.get("from_date"), # value_adjustment_before_from_date condition 1
filters.get("from_date"), # value_adjustment_before_from_date condition 2
filters.get("to_date"), # value_adjustment_till_to_date condition 1
filters.get("to_date"), # value_adjustment_till_to_date condition 2
filters.get("company"), # aca.company_name
filters.get("company"), # a.company
filters.get("to_date"), # a.purchase_date
*asset_names # asset names for IN clause
]
asset_with_value_adjustments = frappe.db.sql(query, values, as_dict=True)
asset_value_adjustment_map = {}
for r in asset_with_value_adjustments:
asset_value_adjustment_map[r["asset"]] = {
"adjustment_before_from_date": flt(r.get("value_adjustment_before_from_date", 0)),
"adjustment_till_to_date": flt(r.get("value_adjustment_till_to_date", 0)),
}
return asset_value_adjustment_map
def get_columns(filters): def get_columns(filters):
"""Создает колонки отчета""" """Создает колонки отчета"""
columns = [] columns = []