fixed taxable assets establishment year report

This commit is contained in:
Ali 2025-12-04 18:16:10 +04:00
parent 76c25a9d49
commit ff5140a8c5
1 changed files with 247 additions and 119 deletions

View File

@ -24,8 +24,8 @@ def get_data(filters):
if not assets_data:
return []
# Получаем расчеты остатков для этих активов
asset_balances = get_asset_balances(filters, [asset['name'] for asset in assets_data])
# Получаем расчеты балансов для этих активов из стандартного отчета
asset_balances = get_asset_balances_from_standard_report(filters, [asset['name'] for asset in assets_data])
# Формируем итоговые данные
data = []
@ -42,20 +42,9 @@ def get_data(filters):
# Находим баланс для этого актива
asset_balance = next((bal for bal in asset_balances if bal['asset'] == asset['name']), {})
# Рассчитываем остатки на начало и конец периода
value_as_on_from_date = flt(asset_balance.get('value_as_on_from_date', 0))
# Берем значения из стандартного отчета
value_of_new_purchase = flt(asset_balance.get('value_of_new_purchase', 0))
value_of_sold_asset = flt(asset_balance.get('value_of_sold_asset', 0))
value_of_scrapped_asset = flt(asset_balance.get('value_of_scrapped_asset', 0))
value_of_capitalized_asset = flt(asset_balance.get('value_of_capitalized_asset', 0))
value_as_on_to_date = (
value_as_on_from_date +
value_of_new_purchase -
value_of_sold_asset -
value_of_scrapped_asset -
value_of_capitalized_asset
)
net_asset_value_as_on_to_date = flt(asset_balance.get('net_asset_value_as_on_to_date', 0))
# Инициализируем все колонки нулями
for asset_type in taxable_asset_types:
@ -67,8 +56,8 @@ def get_data(filters):
# Заполняем колонки для соответствующего типа актива
if asset['taxable_asset_type']:
asset_type_key = get_field_key(asset['taxable_asset_type'])
row[f"{asset_type_key}_value_from"] = value_as_on_from_date
row[f"{asset_type_key}_value_to"] = value_as_on_to_date
row[f"{asset_type_key}_value_from"] = value_of_new_purchase
row[f"{asset_type_key}_value_to"] = net_asset_value_as_on_to_date
row[f"{asset_type_key}_insured"] = row.insured_value
data.append(row)
@ -79,7 +68,6 @@ def get_data(filters):
def get_taxable_asset_types_list():
"""Возвращает список всех типов taxable assets"""
return [
# "Binalar, tikililər və qurğular",
"Çoxmərtəbəli (çoxmənzilli) yaşayış binalar",
"Qeyri-yaşayış binaları (sahələri)",
"Əmlak kompleksi kimi müəssisələr",
@ -98,10 +86,6 @@ def get_field_key(asset_type):
if not asset_type:
return "unknown"
# Создаем ключи для каждого типа актива
# if "Binalar, tikililər və qurğular" in asset_type:
# return "buildings_structures_facilities"
# el
if "Çoxmərtəbəli" in asset_type and "yaşayış binalar" in asset_type:
return "multi_story_residential"
elif "Qeyri-yaşayış binaları" in asset_type:
@ -126,9 +110,24 @@ def get_field_key(asset_type):
return "other_asset_type"
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_establishment_year_taxable_assets(filters, taxable_asset_types):
"""Получает активы с типом 'Vergiyə cəlb olunan əsas vəsaitlər' ТОЛЬКО года создания компании"""
version_info = check_erpnext_version()
conditions = []
values = []
@ -161,7 +160,8 @@ def get_establishment_year_taxable_assets(filters, taxable_asset_types):
if conditions:
where_clause = "WHERE " + " AND ".join(conditions)
# Исключаем капитализированные активы (как в стандартном отчете)
# Исключаем капитализированные активы только если есть поддержка
if version_info["has_capitalization"]:
exclude_capitalized = """
AND NOT EXISTS(
SELECT 1 FROM `tabAsset Capitalization Asset Item` acai
@ -173,6 +173,8 @@ def get_establishment_year_taxable_assets(filters, taxable_asset_types):
"""
where_clause += exclude_capitalized
values.append(filters.get("from_date"))
else:
where_clause += " AND NOT EXISTS(SELECT name FROM `tabAsset Capitalization Asset Item` WHERE asset = a.name)"
query = f"""
SELECT
@ -192,100 +194,229 @@ def get_establishment_year_taxable_assets(filters, taxable_asset_types):
return frappe.db.sql(query, values, as_dict=True)
def get_asset_balances(filters, asset_names):
"""Рассчитывает остатки активов на основе стандартной логики"""
def get_asset_balances_from_standard_report(filters, asset_names):
"""Получает балансы активов используя логику стандартного отчета Asset Depreciations and Balances"""
if not asset_names:
return []
asset_placeholders = ", ".join(["%s"] * len(asset_names))
version_info = check_erpnext_version()
# Используем ту же логику что в стандартном отчете для расчета остатков
query = f"""
SELECT
a.name as asset,
IFNULL(SUM(CASE WHEN a.purchase_date < %s THEN
CASE WHEN IFNULL(a.disposal_date, 0) = 0 OR a.disposal_date >= %s THEN
a.gross_purchase_amount
ELSE
0
END
ELSE
0
END), 0) as value_as_on_from_date,
# Получаем детали активов
asset_details = get_asset_details_for_taxable(filters, asset_names, version_info)
IFNULL(SUM(CASE WHEN a.purchase_date >= %s THEN
a.gross_purchase_amount
ELSE
0
END), 0) as value_of_new_purchase,
# Получаем депрециацию активов
asset_depreciation = get_asset_depreciation_for_taxable(filters, asset_names)
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.gross_purchase_amount
ELSE
0
END
ELSE
0
END), 0) as value_of_sold_asset,
# Объединяем данные
result = []
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.gross_purchase_amount
ELSE
0
END
ELSE
0
END), 0) as value_of_scrapped_asset,
for asset_detail in asset_details:
asset_name = asset_detail.get('name')
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.gross_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(
SELECT 1 FROM `tabAsset Capitalization Asset Item` acai
JOIN `tabAsset Capitalization` ac ON acai.parent = ac.name
WHERE acai.asset = a.name
AND ac.posting_date < %s
AND ac.docstatus = 1
# Находим депреciацию для актива
depreciation = next(
(dep for dep in asset_depreciation if dep['asset'] == asset_name),
{}
)
GROUP BY a.name
# Рассчитываем значения по логике стандартного отчета
value_as_on_from_date = flt(asset_detail.get('cost_as_on_from_date', 0))
value_of_new_purchase = flt(asset_detail.get('cost_of_new_purchase', 0))
value_as_on_to_date = (
value_as_on_from_date +
value_of_new_purchase -
flt(asset_detail.get('cost_of_sold_asset', 0)) -
flt(asset_detail.get('cost_of_scrapped_asset', 0))
)
accumulated_depreciation_as_on_from_date = flt(depreciation.get('accumulated_depreciation_as_on_from_date', 0))
accumulated_depreciation_as_on_to_date = (
accumulated_depreciation_as_on_from_date +
flt(depreciation.get('depreciation_amount_during_the_period', 0)) -
flt(depreciation.get('depreciation_eliminated_during_the_period', 0))
)
net_asset_value_as_on_to_date = value_as_on_to_date - accumulated_depreciation_as_on_to_date
result.append({
'asset': asset_name,
'value_of_new_purchase': value_of_new_purchase,
'net_asset_value_as_on_to_date': net_asset_value_as_on_to_date
})
return result
def get_asset_details_for_taxable(filters, asset_names, version_info):
"""Получает детали активов (совместимо со старой и новой версией)"""
asset_placeholders = ", ".join(["%s"] * len(asset_names))
purchase_amount_field = version_info["purchase_amount_field"]
# Базовый запрос без капитализации
capitalization_check = ""
if version_info["has_capitalization"]:
capitalization_check = """
and not exists(
select 1 from `tabAsset Capitalization Asset Item` acai
join `tabAsset Capitalization` ac on acai.parent=ac.name
where acai.asset = a.name
and ac.posting_date < %s
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
"""
values = [
filters.get("from_date"), # value_as_on_from_date condition 1
filters.get("from_date"), # value_as_on_from_date condition 2
filters.get("from_date"), # value_of_new_purchase
filters.get("from_date"), # value_of_sold_asset condition 1
filters.get("to_date"), # value_of_sold_asset condition 2
filters.get("from_date"), # value_of_scrapped_asset condition 1
filters.get("to_date"), # value_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("from_date"), # cost_as_on_from_date condition 1
filters.get("from_date"), # cost_as_on_from_date condition 2
filters.get("from_date"), # cost_of_new_purchase
filters.get("from_date"), # cost_of_sold_asset condition 1
filters.get("to_date"), # cost_of_sold_asset condition 2
filters.get("from_date"), # cost_of_scrapped_asset condition 1
filters.get("to_date"), # cost_of_scrapped_asset condition 2
filters.get("company"), # company filter
filters.get("to_date"), # purchase_date filter
*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)
def get_asset_depreciation_for_taxable(filters, asset_names):
"""Получает депреciацию активов (совместимо со старой и новой версией)"""
asset_placeholders = ", ".join(["%s"] * len(asset_names))
query = f"""
SELECT results.name as asset,
sum(results.accumulated_depreciation_as_on_from_date) as accumulated_depreciation_as_on_from_date,
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
from (SELECT a.name as name,
ifnull(sum(case when gle.posting_date < %s and (ifnull(a.disposal_date, 0) = 0 or a.disposal_date >= %s) then
gle.debit
else
0
end), 0) as accumulated_depreciation_as_on_from_date,
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
gle.debit
else
0
end), 0) as depreciation_eliminated_during_the_period,
ifnull(sum(case when gle.posting_date >= %s and gle.posting_date <= %s
and (ifnull(a.disposal_date, 0) = 0 or gle.posting_date <= a.disposal_date) then
gle.debit
else
0
end), 0) as depreciation_amount_during_the_period
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
join `tabCompany` company on
company.name = %s
where
a.docstatus=1
and a.company=%s
and a.purchase_date <= %s
and gle.debit != 0
and gle.is_cancelled = 0
and gle.account = ifnull(aca.depreciation_expense_account, company.depreciation_expense_account)
and a.name IN ({asset_placeholders})
group by a.name
union
SELECT a.name as name,
ifnull(sum(case when ifnull(a.disposal_date, 0) != 0 and (a.disposal_date < %s or a.disposal_date > %s) then
0
else
a.opening_accumulated_depreciation
end), 0) as accumulated_depreciation_as_on_from_date,
ifnull(sum(case when a.disposal_date >= %s and a.disposal_date <= %s then
a.opening_accumulated_depreciation
else
0
end), 0) as depreciation_eliminated_during_the_period,
0 as depreciation_amount_during_the_period
from `tabAsset` a
where a.docstatus=1 and a.company=%s and a.purchase_date <= %s
and a.name IN ({asset_placeholders})
group by a.name) as results
group by results.name
"""
values = [
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"), # depreciation_eliminated_during_the_period condition 1
filters.get("to_date"), # depreciation_eliminated_during_the_period condition 2
filters.get("from_date"), # depreciation_amount_during_the_period condition 1
filters.get("to_date"), # depreciation_amount_during_the_period condition 2
filters.get("company"), # aca.company_name
filters.get("company"), # company.name
filters.get("company"), # a.company
filters.get("to_date"), # a.purchase_date
*asset_names, # asset names for IN clause (first 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("to_date"), # disposal_date condition (second union)
filters.get("company"), # a.company (second union)
filters.get("to_date"), # a.purchase_date (second union)
*asset_names # asset names for IN clause (second union)
]
return frappe.db.sql(query, values, as_dict=True)
@ -347,9 +478,6 @@ def get_columns(filters):
def get_short_asset_type_name(asset_type):
"""Создает короткое название для заголовка колонки"""
# if "Binalar, tikililər və qurğular" in asset_type:
# return "Binalar və Qurğular"
# el
if "Çoxmərtəbəli" in asset_type and "yaşayış binalar" in asset_type:
return "Çoxmərtəbəli Binaları"
elif "Qeyri-yaşayış binaları" in asset_type: