From e5f603c9d9d4cb2668cccb3f3c7e287be79c232e Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Wed, 1 Mar 2023 14:48:06 +0530 Subject: [PATCH] perf: Apply closing balance in Trial Balance report --- .../report/trial_balance/trial_balance.py | 132 +++++++++++------- 1 file changed, 79 insertions(+), 53 deletions(-) diff --git a/erpnext/accounts/report/trial_balance/trial_balance.py b/erpnext/accounts/report/trial_balance/trial_balance.py index 3af01fde7d0..96cb38ba2ab 100644 --- a/erpnext/accounts/report/trial_balance/trial_balance.py +++ b/erpnext/accounts/report/trial_balance/trial_balance.py @@ -4,7 +4,8 @@ import frappe from frappe import _ -from frappe.utils import cstr, flt, formatdate, getdate +from frappe.query_builder.functions import Sum +from frappe.utils import add_days, cstr, flt, formatdate, getdate import erpnext from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( @@ -140,45 +141,88 @@ def get_opening_balances(filters): def get_rootwise_opening_balances(filters, report_type): - additional_conditions = "" - if not filters.show_unclosed_fy_pl_balances: - additional_conditions = ( - " and posting_date >= %(year_start_date)s" if report_type == "Profit and Loss" else "" + gle = [] + accounting_dimensions = get_accounting_dimensions(as_list=False) + gle = get_opening_balance("Closing Balance", filters, report_type, accounting_dimensions) + + last_period_closing_voucher_date = frappe.db.get_value( + "Period Closing Voucher", {"docstatus": 1, "company": filters.company}, "max(posting_date)" + ) + + # Check If need to get opening balance from GL Entry + if getdate(last_period_closing_voucher_date) < getdate(add_days(filters.from_date, -1)): + filters.from_date = add_days(last_period_closing_voucher_date, 1) + gle = get_opening_balance("GL Entry", filters, report_type, accounting_dimensions) + + opening = frappe._dict() + for d in gle: + opening.setdefault(d.account, d) + + return opening + + +def get_opening_balance(doctype, filters, report_type, accounting_dimensions): + closing_balance = frappe.qb.DocType(doctype) + account = frappe.qb.DocType("Account") + + opening_balance = ( + frappe.qb.from_(closing_balance) + .select( + closing_balance.account, + Sum(closing_balance.debit).as_("opening_debit"), + Sum(closing_balance.credit).as_("opening_credit"), ) + .where( + (closing_balance.company == filters.company) + & ( + closing_balance.account.isin( + frappe.qb.from_("account").select("name").where(account.report_type == report_type) + ) + ) + ) + .groupby(closing_balance.account) + ) + + if doctype == "Closing Balance": + opening_balance = opening_balance.where(closing_balance.closing_date < filters.from_date) + else: + opening_balance = opening_balance.where(closing_balance.posting_date < filters.from_date) + + if not filters.show_unclosed_fy_pl_balances and report_type == "Profit and Loss": + opening_balance = opening_balance.where(closing_balance.closing_date >= filters.year_start_date) if not flt(filters.with_period_closing_entry): - additional_conditions += " and ifnull(voucher_type, '')!='Period Closing Voucher'" + if doctype == "Closing Balance": + opening_balance = opening_balance.where(closing_balance.is_period_closing_voucher_entry == 0) + else: + opening_balance = opening_balance.where( + closing_balance.voucher_type != "Period Closing Voucher" + ) if filters.cost_center: lft, rgt = frappe.db.get_value("Cost Center", filters.cost_center, ["lft", "rgt"]) - additional_conditions += """ and cost_center in (select name from `tabCost Center` - where lft >= %s and rgt <= %s)""" % ( - lft, - rgt, + cost_center = frappe.qb.DocType("Cost Center") + opening_balance = opening_balance.where( + closing_balance.cost_center.in_( + frappe.qb.from_(cost_center) + .select("name") + .where((cost_center.lft >= lft) & (cost_center.rgt <= rgt)) + ) ) if filters.project: - additional_conditions += " and project = %(project)s" + opening_balance = opening_balance.where(closing_balance.project == filters.project) if filters.get("include_default_book_entries"): - additional_conditions += ( - " AND (finance_book in (%(finance_book)s, %(company_fb)s, '') OR finance_book IS NULL)" + opening_balance = opening_balance.where( + (closing_balance.finance_book.isin([cstr(filters.finance_book), cstr(filters.company_fb), ""])) + | (closing_balance.finance_book.isnull()) ) else: - additional_conditions += " AND (finance_book in (%(finance_book)s, '') OR finance_book IS NULL)" - - accounting_dimensions = get_accounting_dimensions(as_list=False) - - query_filters = { - "company": filters.company, - "from_date": filters.from_date, - "to_date": filters.to_date, - "report_type": report_type, - "year_start_date": filters.year_start_date, - "project": filters.project, - "finance_book": filters.finance_book, - "company_fb": frappe.get_cached_value("Company", filters.company, "default_finance_book"), - } + opening_balance = opening_balance.where( + (closing_balance.finance_book.isin([cstr(filters.finance_book), ""])) + | (closing_balance.finance_book.isnull()) + ) if accounting_dimensions: for dimension in accounting_dimensions: @@ -187,35 +231,17 @@ def get_rootwise_opening_balances(filters, report_type): filters[dimension.fieldname] = get_dimension_with_children( dimension.document_type, filters.get(dimension.fieldname) ) - additional_conditions += " and {0} in %({0})s".format(dimension.fieldname) + opening_balance = opening_balance.where( + closing_balance[dimension.fieldname].isin(filters[dimension.fieldname]) + ) else: - additional_conditions += " and {0} in %({0})s".format(dimension.fieldname) + opening_balance = opening_balance.where( + closing_balance[dimension.fieldname].isin(filters[dimension.fieldname]) + ) - query_filters.update({dimension.fieldname: filters.get(dimension.fieldname)}) + gle = opening_balance.run(as_dict=1) - gle = frappe.db.sql( - """ - select - account, sum(debit) as opening_debit, sum(credit) as opening_credit - from `tabGL Entry` - where - company=%(company)s - {additional_conditions} - and (posting_date < %(from_date)s or (ifnull(is_opening, 'No') = 'Yes' and posting_date <= %(to_date)s)) - and account in (select name from `tabAccount` where report_type=%(report_type)s) - and is_cancelled = 0 - group by account""".format( - additional_conditions=additional_conditions - ), - query_filters, - as_dict=True, - ) - - opening = frappe._dict() - for d in gle: - opening.setdefault(d.account, d) - - return opening + return gle def calculate_values(accounts, gl_entries_by_account, opening_balances, filters, company_currency):