diff --git a/taxes_az/taxes_az/report/tax_exempt_assets_report/tax_exempt_assets_report.py b/taxes_az/taxes_az/report/tax_exempt_assets_report/tax_exempt_assets_report.py index bf1112c..9755744 100644 --- a/taxes_az/taxes_az/report/tax_exempt_assets_report/tax_exempt_assets_report.py +++ b/taxes_az/taxes_az/report/tax_exempt_assets_report/tax_exempt_assets_report.py @@ -147,9 +147,24 @@ def get_field_key(tax_article): 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): """Получает активы с tax exempt статьями исключая активы года создания компании""" + version_info = check_erpnext_version() + conditions = [] values = [] @@ -178,18 +193,22 @@ def get_assets_with_tax_exempt_articles(filters, tax_exempt_articles): if conditions: where_clause = "WHERE " + " AND ".join(conditions) - # Исключаем капитализированные активы (как в стандартном отчете) - exclude_capitalized = """ - 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 - ) - """ - where_clause += exclude_capitalized - values.append(filters.get("from_date")) + # Исключаем капитализированные активы только если есть поддержка + if version_info["has_capitalization"]: + exclude_capitalized = """ + 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 + ) + """ + where_clause += exclude_capitalized + 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""" SELECT @@ -215,15 +234,14 @@ def get_asset_balances_from_standard_report(filters, asset_names): if not asset_names: 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_value_adjustments = get_asset_value_adjustments_for_tax_exempt(filters, asset_names) - # Объединяем данные 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']) - 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_from_date = flt(asset_detail.get('cost_as_on_from_date', 0)) value_as_on_to_date = ( value_as_on_from_date + - flt(asset_detail.get('value_of_new_purchase', 0)) - - flt(asset_detail.get('value_of_sold_asset', 0)) - - flt(asset_detail.get('value_of_scrapped_asset', 0)) - - flt(asset_detail.get('value_of_capitalized_asset', 0)) + - adjustment_during_period + flt(asset_detail.get('cost_of_new_purchase', 0)) - + 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)) @@ -263,8 +269,7 @@ def get_asset_balances_from_standard_report(filters, asset_names): 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)) - - flt(depreciation.get('depreciation_eliminated_via_reversal', 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 @@ -278,101 +283,98 @@ def get_asset_balances_from_standard_report(filters, asset_names): 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)) + purchase_amount_field = version_info["purchase_amount_field"] - 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.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( + # Базовый запрос без капитализации + 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_tax_exempt(filters, asset_names): - """Получает депреciацию активов (из стандартного отчета)""" + """Получает депре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_via_reversal) as depreciation_eliminated_via_reversal, 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, @@ -381,11 +383,6 @@ def get_asset_depreciation_for_tax_exempt(filters, asset_names): else 0 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 and a.disposal_date <= %s and gle.posting_date <= a.disposal_date then gle.debit @@ -409,18 +406,18 @@ def get_asset_depreciation_for_tax_exempt(filters, asset_names): 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 then + 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, - 0 as depreciation_as_on_from_date_credit, ifnull(sum(case when a.disposal_date >= %s and a.disposal_date <= %s then a.opening_accumulated_depreciation else @@ -437,7 +434,6 @@ def get_asset_depreciation_for_tax_exempt(filters, asset_names): 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("to_date"), # depreciation_eliminated_via_reversal 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 @@ -448,6 +444,7 @@ def get_asset_depreciation_for_tax_exempt(filters, asset_names): 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) @@ -458,73 +455,6 @@ def get_asset_depreciation_for_tax_exempt(filters, asset_names): 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): """Создает колонки отчета""" columns = []