mirror of
https://github.com/frappe/erpnext.git
synced 2026-08-31 23:33:43 +00:00
Merge pull request #56051 from mihir-kandoi/pg-accounts-statements
refactor(postgres): port Accounts statement & ledger report queries to the query builder
This commit is contained in:
@@ -15,10 +15,7 @@ def execute(filters=None):
|
|||||||
|
|
||||||
def get_data(filters):
|
def get_data(filters):
|
||||||
data = []
|
data = []
|
||||||
depreciation_accounts = frappe.db.sql_list(
|
depreciation_accounts = frappe.get_all("Account", filters={"account_type": "Depreciation"}, pluck="name")
|
||||||
""" select name from tabAccount
|
|
||||||
where ifnull(account_type, '') = 'Depreciation' """
|
|
||||||
)
|
|
||||||
|
|
||||||
filters_data = [
|
filters_data = [
|
||||||
["company", "=", filters.get("company")],
|
["company", "=", filters.get("company")],
|
||||||
@@ -33,10 +30,8 @@ def get_data(filters):
|
|||||||
filters_data.append(["against_voucher", "=", filters.get("asset")])
|
filters_data.append(["against_voucher", "=", filters.get("asset")])
|
||||||
|
|
||||||
if filters.get("asset_category"):
|
if filters.get("asset_category"):
|
||||||
assets = frappe.db.sql_list(
|
assets = frappe.get_all(
|
||||||
"""select name from tabAsset
|
"Asset", filters={"asset_category": filters.get("asset_category"), "docstatus": 1}, pluck="name"
|
||||||
where asset_category = %s and docstatus=1""",
|
|
||||||
filters.get("asset_category"),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
filters_data.append(["against_voucher", "in", assets])
|
filters_data.append(["against_voucher", "in", assets])
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
import frappe
|
||||||
|
|
||||||
|
from erpnext.accounts.report.asset_depreciation_ledger.asset_depreciation_ledger import execute
|
||||||
|
from erpnext.tests.utils import ERPNextTestSuite
|
||||||
|
|
||||||
|
|
||||||
|
class TestAssetDepreciationLedger(ERPNextTestSuite):
|
||||||
|
def test_report_executes(self):
|
||||||
|
# Smoke-guards the raw-SQL -> query-builder port: the report query must compile and run on
|
||||||
|
# both MariaDB and postgres.
|
||||||
|
company = frappe.db.get_value("Company", {}, "name")
|
||||||
|
columns, *_rest = execute(
|
||||||
|
frappe._dict({"company": company, "from_date": "2020-01-01", "to_date": "2030-12-31"})
|
||||||
|
)
|
||||||
|
self.assertTrue(columns)
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.query_builder import CustomFunction
|
from frappe.query_builder.custom import MonthName
|
||||||
from frappe.utils import add_months, flt, formatdate
|
from frappe.utils import add_months, flt, formatdate
|
||||||
|
|
||||||
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_dimensions
|
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_dimensions
|
||||||
@@ -113,7 +113,6 @@ def build_budget_map(budget_records, filters):
|
|||||||
|
|
||||||
def get_actual_transactions(dimension_name, filters):
|
def get_actual_transactions(dimension_name, filters):
|
||||||
budget_against = frappe.scrub(filters.get("budget_against"))
|
budget_against = frappe.scrub(filters.get("budget_against"))
|
||||||
monthname = CustomFunction("MONTHNAME", ["date"])
|
|
||||||
|
|
||||||
gle = frappe.qb.DocType("GL Entry")
|
gle = frappe.qb.DocType("GL Entry")
|
||||||
budget = frappe.qb.DocType("Budget")
|
budget = frappe.qb.DocType("Budget")
|
||||||
@@ -126,7 +125,7 @@ def get_actual_transactions(dimension_name, filters):
|
|||||||
gle.debit,
|
gle.debit,
|
||||||
gle.credit,
|
gle.credit,
|
||||||
gle.fiscal_year,
|
gle.fiscal_year,
|
||||||
monthname(gle.posting_date).as_("month_name"),
|
MonthName(gle.posting_date).as_("month_name"),
|
||||||
budget[budget_against].as_("budget_against"),
|
budget[budget_against].as_("budget_against"),
|
||||||
)
|
)
|
||||||
.where(
|
.where(
|
||||||
@@ -137,7 +136,10 @@ def get_actual_transactions(dimension_name, filters):
|
|||||||
& (gle.is_cancelled == 0)
|
& (gle.is_cancelled == 0)
|
||||||
& (budget[budget_against] == dimension_name)
|
& (budget[budget_against] == dimension_name)
|
||||||
)
|
)
|
||||||
.groupby(gle.name)
|
# budget[budget_against] is selected from the Budget table, which is not functionally
|
||||||
|
# dependent on the grouped GL Entry PK, so postgres requires it in the GROUP BY. The WHERE
|
||||||
|
# pins it to dimension_name (a constant), so grouping by it does not change the result.
|
||||||
|
.groupby(gle.name, budget[budget_against])
|
||||||
.orderby(gle.fiscal_year)
|
.orderby(gle.fiscal_year)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -157,15 +159,11 @@ def get_actual_transactions(dimension_name, filters):
|
|||||||
|
|
||||||
|
|
||||||
def get_budget_distributions(budget):
|
def get_budget_distributions(budget):
|
||||||
return frappe.db.sql(
|
return frappe.get_all(
|
||||||
"""
|
"Budget Distribution",
|
||||||
SELECT start_date, end_date, amount, percent
|
filters={"parent": budget.name},
|
||||||
FROM `tabBudget Distribution`
|
fields=["start_date", "end_date", "amount", "percent"],
|
||||||
WHERE parent = %s
|
order_by="start_date asc",
|
||||||
ORDER BY start_date ASC
|
|
||||||
""",
|
|
||||||
(budget.name,),
|
|
||||||
as_dict=True,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -351,20 +349,16 @@ def get_columns(filters):
|
|||||||
|
|
||||||
|
|
||||||
def get_fiscal_years(filters):
|
def get_fiscal_years(filters):
|
||||||
fiscal_year = frappe.db.sql(
|
return frappe.get_all(
|
||||||
"""
|
"Fiscal Year",
|
||||||
select
|
filters={"name": ["between", [filters["from_fiscal_year"], filters["to_fiscal_year"]]]},
|
||||||
name
|
fields=["name"],
|
||||||
from
|
# the raw query had no ORDER BY (de-facto oldest-first); get_all would otherwise apply the
|
||||||
`tabFiscal Year`
|
# Fiscal Year doctype default (name DESC) and reverse column order / cumulative-mode values.
|
||||||
where
|
order_by="name asc",
|
||||||
name between %(from_fiscal_year)s and %(to_fiscal_year)s
|
as_list=True,
|
||||||
""",
|
|
||||||
{"from_fiscal_year": filters["from_fiscal_year"], "to_fiscal_year": filters["to_fiscal_year"]},
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return fiscal_year
|
|
||||||
|
|
||||||
|
|
||||||
def get_cost_center_with_children(cost_centers):
|
def get_cost_center_with_children(cost_centers):
|
||||||
"""Expand each cost center to include itself and all its descendants."""
|
"""Expand each cost center to include itself and all its descendants."""
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
# Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
import frappe
|
||||||
|
|
||||||
|
from erpnext.accounts.report.budget_variance_report.budget_variance_report import execute
|
||||||
|
from erpnext.tests.utils import ERPNextTestSuite
|
||||||
|
|
||||||
|
|
||||||
|
class TestBudgetVarianceReport(ERPNextTestSuite):
|
||||||
|
def test_report_executes(self):
|
||||||
|
# Smoke-guards the raw-SQL -> query-builder port: the report query must compile and run on
|
||||||
|
# both MariaDB and postgres.
|
||||||
|
company = frappe.db.get_value("Company", {}, "name")
|
||||||
|
fy = frappe.db.get_value("Fiscal Year", {}, "name", order_by="year_start_date desc")
|
||||||
|
columns, *_rest = execute(
|
||||||
|
frappe._dict(
|
||||||
|
{
|
||||||
|
"company": company,
|
||||||
|
"from_fiscal_year": fy,
|
||||||
|
"to_fiscal_year": fy,
|
||||||
|
"period": "Yearly",
|
||||||
|
"budget_against": "Cost Center",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.assertTrue(columns)
|
||||||
@@ -7,6 +7,7 @@ from datetime import timedelta
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.query_builder import DocType
|
from frappe.query_builder import DocType
|
||||||
|
from frappe.query_builder.functions import Sum
|
||||||
from frappe.utils import cstr, flt
|
from frappe.utils import cstr, flt
|
||||||
from pypika import Order
|
from pypika import Order
|
||||||
|
|
||||||
@@ -213,37 +214,43 @@ def get_account_type_based_data(company, account_type, period_list, accumulated_
|
|||||||
|
|
||||||
|
|
||||||
def get_account_type_based_gl_data(company, filters=None):
|
def get_account_type_based_gl_data(company, filters=None):
|
||||||
cond = ""
|
|
||||||
filters = frappe._dict(filters or {})
|
filters = frappe._dict(filters or {})
|
||||||
|
|
||||||
|
gle = frappe.qb.DocType("GL Entry")
|
||||||
|
account = frappe.qb.DocType("Account")
|
||||||
|
|
||||||
|
query = (
|
||||||
|
frappe.qb.from_(gle)
|
||||||
|
.select(Sum(gle.credit) - Sum(gle.debit))
|
||||||
|
.where(
|
||||||
|
(gle.company == company)
|
||||||
|
& (gle.posting_date >= filters.start_date)
|
||||||
|
& (gle.posting_date <= filters.end_date)
|
||||||
|
& (gle.voucher_type != "Period Closing Voucher")
|
||||||
|
& gle.account.isin(
|
||||||
|
frappe.qb.from_(account)
|
||||||
|
.select(account.name)
|
||||||
|
.where(account.account_type == filters.account_type)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
if filters.include_default_book_entries:
|
if filters.include_default_book_entries:
|
||||||
company_fb = frappe.get_cached_value("Company", company, "default_finance_book")
|
company_fb = frappe.get_cached_value("Company", company, "default_finance_book")
|
||||||
cond = """ AND (finance_book in ({}, {}, '') OR finance_book IS NULL)
|
query = query.where(
|
||||||
""".format(
|
gle.finance_book.isin([filters.finance_book, company_fb, ""]) | gle.finance_book.isnull()
|
||||||
frappe.db.escape(filters.finance_book),
|
|
||||||
frappe.db.escape(company_fb),
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
cond = " AND (finance_book in (%s, '') OR finance_book IS NULL)" % (
|
query = query.where(
|
||||||
frappe.db.escape(cstr(filters.finance_book))
|
gle.finance_book.isin([cstr(filters.finance_book), ""]) | gle.finance_book.isnull()
|
||||||
)
|
)
|
||||||
|
|
||||||
if filters.get("cost_center"):
|
if filters.get("cost_center"):
|
||||||
filters.cost_center = get_cost_centers_with_children(filters.cost_center)
|
cost_centers = get_cost_centers_with_children(filters.cost_center)
|
||||||
cond += " and cost_center in %(cost_center)s"
|
query = query.where(gle.cost_center.isin(cost_centers))
|
||||||
|
|
||||||
gl_sum = frappe.db.sql_list(
|
gl_sum = query.run()
|
||||||
f"""
|
return gl_sum[0][0] if gl_sum and gl_sum[0][0] else 0
|
||||||
select sum(credit) - sum(debit)
|
|
||||||
from `tabGL Entry`
|
|
||||||
where company=%(company)s and posting_date >= %(start_date)s and posting_date <= %(end_date)s
|
|
||||||
and voucher_type != 'Period Closing Voucher'
|
|
||||||
and account in ( SELECT name FROM tabAccount WHERE account_type = %(account_type)s) {cond}
|
|
||||||
""",
|
|
||||||
filters,
|
|
||||||
)
|
|
||||||
|
|
||||||
return gl_sum[0] if gl_sum and gl_sum[0] else 0
|
|
||||||
|
|
||||||
|
|
||||||
def get_start_date(period, accumulated_values, company):
|
def get_start_date(period, accumulated_values, company):
|
||||||
@@ -367,11 +374,10 @@ def get_net_income(company, period_list, filters):
|
|||||||
from_date, to_date = get_opening_range_using_fiscal_year(company, period_list)
|
from_date, to_date = get_opening_range_using_fiscal_year(company, period_list)
|
||||||
|
|
||||||
for root_type in ["Income", "Expense"]:
|
for root_type in ["Income", "Expense"]:
|
||||||
for root in frappe.db.sql(
|
for root in frappe.get_all(
|
||||||
"""select lft, rgt from tabAccount
|
"Account",
|
||||||
where root_type=%s and ifnull(parent_account, '') = ''""",
|
filters={"root_type": root_type, "parent_account": ["is", "not set"]},
|
||||||
root_type,
|
fields=["lft", "rgt"],
|
||||||
as_dict=1,
|
|
||||||
):
|
):
|
||||||
set_gl_entries_by_account(
|
set_gl_entries_by_account(
|
||||||
company,
|
company,
|
||||||
|
|||||||
27
erpnext/accounts/report/cash_flow/test_cash_flow.py
Normal file
27
erpnext/accounts/report/cash_flow/test_cash_flow.py
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
import frappe
|
||||||
|
|
||||||
|
from erpnext.accounts.report.cash_flow.cash_flow import execute
|
||||||
|
from erpnext.tests.utils import ERPNextTestSuite
|
||||||
|
|
||||||
|
|
||||||
|
class TestCashFlow(ERPNextTestSuite):
|
||||||
|
def test_report_executes(self):
|
||||||
|
# Smoke-guards the raw-SQL -> query-builder port: the report query must compile and run on
|
||||||
|
# both MariaDB and postgres.
|
||||||
|
company = frappe.db.get_value("Company", {}, "name")
|
||||||
|
fy = frappe.db.get_value("Fiscal Year", {}, "name", order_by="year_start_date desc")
|
||||||
|
columns, *_rest = execute(
|
||||||
|
frappe._dict(
|
||||||
|
{
|
||||||
|
"company": company,
|
||||||
|
"from_fiscal_year": fy,
|
||||||
|
"to_fiscal_year": fy,
|
||||||
|
"filter_based_on": "Fiscal Year",
|
||||||
|
"periodicity": "Yearly",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.assertTrue(columns)
|
||||||
@@ -347,11 +347,10 @@ def get_data(companies, root_type, balance_must_be, fiscal_year, filters=None, i
|
|||||||
filters.end_date = end_date
|
filters.end_date = end_date
|
||||||
|
|
||||||
gl_entries_by_account = {}
|
gl_entries_by_account = {}
|
||||||
for root in frappe.db.sql(
|
for root in frappe.get_all(
|
||||||
"""select lft, rgt from tabAccount
|
"Account",
|
||||||
where root_type=%s and ifnull(parent_account, '') = ''""",
|
filters={"root_type": root_type, "parent_account": ["is", "not set"]},
|
||||||
root_type,
|
fields=["lft", "rgt"],
|
||||||
as_dict=1,
|
|
||||||
):
|
):
|
||||||
set_gl_entries_by_account(
|
set_gl_entries_by_account(
|
||||||
start_date,
|
start_date,
|
||||||
@@ -512,9 +511,11 @@ def get_companies(filters):
|
|||||||
def get_subsidiary_companies(company):
|
def get_subsidiary_companies(company):
|
||||||
lft, rgt = frappe.get_cached_value("Company", company, ["lft", "rgt"])
|
lft, rgt = frappe.get_cached_value("Company", company, ["lft", "rgt"])
|
||||||
|
|
||||||
return frappe.db.sql_list(
|
return frappe.get_all(
|
||||||
f"""select name from `tabCompany`
|
"Company",
|
||||||
where lft >= {lft} and rgt <= {rgt} order by lft, rgt"""
|
filters={"lft": [">=", lft], "rgt": ["<=", rgt]},
|
||||||
|
pluck="name",
|
||||||
|
order_by="lft, rgt",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -604,14 +605,10 @@ def set_gl_entries_by_account(
|
|||||||
|
|
||||||
company_lft, company_rgt = frappe.get_cached_value("Company", filters.get("company"), ["lft", "rgt"])
|
company_lft, company_rgt = frappe.get_cached_value("Company", filters.get("company"), ["lft", "rgt"])
|
||||||
|
|
||||||
companies = frappe.db.sql(
|
companies = frappe.get_all(
|
||||||
""" select name, default_currency from `tabCompany`
|
"Company",
|
||||||
where lft >= %(company_lft)s and rgt <= %(company_rgt)s""",
|
filters={"lft": [">=", company_lft], "rgt": ["<=", company_rgt]},
|
||||||
{
|
fields=["name", "default_currency"],
|
||||||
"company_lft": company_lft,
|
|
||||||
"company_rgt": company_rgt,
|
|
||||||
},
|
|
||||||
as_dict=1,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
currency_info = frappe._dict(
|
currency_info = frappe._dict(
|
||||||
|
|||||||
@@ -126,12 +126,22 @@ def get_data(filters) -> list[list]:
|
|||||||
|
|
||||||
|
|
||||||
def get_company_wise_tb_data(filters, reporting_currency, ignore_reporting_currency):
|
def get_company_wise_tb_data(filters, reporting_currency, ignore_reporting_currency):
|
||||||
accounts = frappe.db.sql(
|
accounts = frappe.get_all(
|
||||||
"""select name, account_number, parent_account, account_name, root_type, report_type, account_type, is_group, lft, rgt
|
"Account",
|
||||||
|
filters={"company": filters.company},
|
||||||
from `tabAccount` where company=%s order by lft""",
|
fields=[
|
||||||
filters.company,
|
"name",
|
||||||
as_dict=True,
|
"account_number",
|
||||||
|
"parent_account",
|
||||||
|
"account_name",
|
||||||
|
"root_type",
|
||||||
|
"report_type",
|
||||||
|
"account_type",
|
||||||
|
"is_group",
|
||||||
|
"lft",
|
||||||
|
"rgt",
|
||||||
|
],
|
||||||
|
order_by="lft",
|
||||||
)
|
)
|
||||||
|
|
||||||
ignore_is_opening = frappe.get_single_value("Accounts Settings", "ignore_is_opening_check_for_reporting")
|
ignore_is_opening = frappe.get_single_value("Accounts Settings", "ignore_is_opening_check_for_reporting")
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import cstr, flt
|
from frappe.utils import flt
|
||||||
|
|
||||||
import erpnext
|
import erpnext
|
||||||
from erpnext.accounts.report.financial_statements import (
|
from erpnext.accounts.report.financial_statements import (
|
||||||
@@ -31,18 +31,23 @@ def execute(filters=None):
|
|||||||
def get_data(filters, dimension_list):
|
def get_data(filters, dimension_list):
|
||||||
company_currency = erpnext.get_company_currency(filters.company)
|
company_currency = erpnext.get_company_currency(filters.company)
|
||||||
|
|
||||||
acc = frappe.db.sql(
|
acc = frappe.get_all(
|
||||||
"""
|
"Account",
|
||||||
select
|
filters={"company": filters.company},
|
||||||
name, account_number, parent_account, lft, rgt, root_type,
|
fields=[
|
||||||
report_type, account_name, include_in_gross, account_type, is_group
|
"name",
|
||||||
from
|
"account_number",
|
||||||
`tabAccount`
|
"parent_account",
|
||||||
where
|
"lft",
|
||||||
company=%s
|
"rgt",
|
||||||
order by lft""",
|
"root_type",
|
||||||
(filters.company),
|
"report_type",
|
||||||
as_dict=True,
|
"account_name",
|
||||||
|
"include_in_gross",
|
||||||
|
"account_type",
|
||||||
|
"is_group",
|
||||||
|
],
|
||||||
|
order_by="lft",
|
||||||
)
|
)
|
||||||
|
|
||||||
if not acc:
|
if not acc:
|
||||||
@@ -50,16 +55,17 @@ def get_data(filters, dimension_list):
|
|||||||
|
|
||||||
accounts, accounts_by_name, parent_children_map = filter_accounts(acc)
|
accounts, accounts_by_name, parent_children_map = filter_accounts(acc)
|
||||||
|
|
||||||
min_lft, max_rgt = frappe.db.sql(
|
lft_rgt = frappe.get_all(
|
||||||
"""select min(lft), max(rgt) from `tabAccount`
|
"Account",
|
||||||
where company=%s""",
|
filters={"company": filters.company},
|
||||||
(filters.company),
|
fields=[{"MIN": "lft", "as": "min_lft"}, {"MAX": "rgt", "as": "max_rgt"}],
|
||||||
)[0]
|
)[0]
|
||||||
|
min_lft, max_rgt = lft_rgt.min_lft, lft_rgt.max_rgt
|
||||||
|
|
||||||
account = frappe.db.sql_list(
|
account = frappe.get_all(
|
||||||
"""select name from `tabAccount`
|
"Account",
|
||||||
where lft >= %s and rgt <= %s and company = %s""",
|
filters={"lft": [">=", min_lft], "rgt": ["<=", max_rgt], "company": filters.company},
|
||||||
(min_lft, max_rgt, filters.company),
|
pluck="name",
|
||||||
)
|
)
|
||||||
|
|
||||||
gl_entries_by_account = {}
|
gl_entries_by_account = {}
|
||||||
@@ -75,42 +81,34 @@ def get_data(filters, dimension_list):
|
|||||||
|
|
||||||
|
|
||||||
def set_gl_entries_by_account(dimension_list, filters, account, gl_entries_by_account):
|
def set_gl_entries_by_account(dimension_list, filters, account, gl_entries_by_account):
|
||||||
condition = get_condition(filters.get("dimension"))
|
dimension_field = frappe.scrub(filters.get("dimension"))
|
||||||
|
|
||||||
if account:
|
|
||||||
condition += " and account in ({})".format(", ".join([frappe.db.escape(d) for d in account]))
|
|
||||||
|
|
||||||
gl_filters = {
|
gl_filters = {
|
||||||
"company": filters.get("company"),
|
"company": filters.get("company"),
|
||||||
"from_date": filters.get("from_date"),
|
dimension_field: ["in", list(set(dimension_list))],
|
||||||
"to_date": filters.get("to_date"),
|
"posting_date": ["between", [filters.get("from_date"), filters.get("to_date")]],
|
||||||
"finance_book": cstr(filters.get("finance_book")),
|
"is_cancelled": 0,
|
||||||
}
|
}
|
||||||
|
if account:
|
||||||
|
gl_filters["account"] = ["in", account]
|
||||||
|
|
||||||
gl_filters["dimensions"] = tuple(set(dimension_list))
|
gl_entries = frappe.get_all(
|
||||||
|
"GL Entry",
|
||||||
if filters.get("include_default_book_entries"):
|
filters=gl_filters,
|
||||||
gl_filters["company_fb"] = frappe.get_cached_value("Company", filters.company, "default_finance_book")
|
fields=[
|
||||||
|
"posting_date",
|
||||||
gl_entries = frappe.db.sql(
|
"account",
|
||||||
"""
|
dimension_field,
|
||||||
select
|
"debit",
|
||||||
posting_date, account, {dimension}, debit, credit, is_opening, fiscal_year,
|
"credit",
|
||||||
debit_in_account_currency, credit_in_account_currency, account_currency
|
"is_opening",
|
||||||
from
|
"fiscal_year",
|
||||||
`tabGL Entry`
|
"debit_in_account_currency",
|
||||||
where
|
"credit_in_account_currency",
|
||||||
company=%(company)s
|
"account_currency",
|
||||||
{condition}
|
],
|
||||||
and posting_date >= %(from_date)s
|
order_by="account, posting_date",
|
||||||
and posting_date <= %(to_date)s
|
)
|
||||||
and is_cancelled = 0
|
|
||||||
order by account, posting_date""".format(
|
|
||||||
dimension=frappe.scrub(filters.get("dimension")), condition=condition
|
|
||||||
),
|
|
||||||
gl_filters,
|
|
||||||
as_dict=True,
|
|
||||||
) # nosec
|
|
||||||
|
|
||||||
for entry in gl_entries:
|
for entry in gl_entries:
|
||||||
gl_entries_by_account.setdefault(entry.account, []).append(entry)
|
gl_entries_by_account.setdefault(entry.account, []).append(entry)
|
||||||
@@ -178,14 +176,6 @@ def accumulate_values_into_parents(accounts, accounts_by_name, dimension_list):
|
|||||||
].get(frappe.scrub(dimension), 0.0) + d.get(frappe.scrub(dimension), 0.0)
|
].get(frappe.scrub(dimension), 0.0) + d.get(frappe.scrub(dimension), 0.0)
|
||||||
|
|
||||||
|
|
||||||
def get_condition(dimension):
|
|
||||||
conditions = []
|
|
||||||
|
|
||||||
conditions.append(f"{frappe.scrub(dimension)} in %(dimensions)s")
|
|
||||||
|
|
||||||
return " and {}".format(" and ".join(conditions)) if conditions else ""
|
|
||||||
|
|
||||||
|
|
||||||
def get_dimensions(filters):
|
def get_dimensions(filters):
|
||||||
meta = frappe.get_meta(filters.get("dimension"), cached=False)
|
meta = frappe.get_meta(filters.get("dimension"), cached=False)
|
||||||
query_filters = {}
|
query_filters = {}
|
||||||
|
|||||||
@@ -179,11 +179,10 @@ def get_data(
|
|||||||
company_currency = get_appropriate_currency(company, filters)
|
company_currency = get_appropriate_currency(company, filters)
|
||||||
|
|
||||||
gl_entries_by_account = {}
|
gl_entries_by_account = {}
|
||||||
for root in frappe.db.sql(
|
for root in frappe.get_all(
|
||||||
"""select lft, rgt from tabAccount
|
"Account",
|
||||||
where root_type=%s and ifnull(parent_account, '') = ''""",
|
filters={"root_type": root_type, "parent_account": ["is", "not set"]},
|
||||||
root_type,
|
fields=["lft", "rgt"],
|
||||||
as_dict=1,
|
|
||||||
):
|
):
|
||||||
set_gl_entries_by_account(
|
set_gl_entries_by_account(
|
||||||
company,
|
company,
|
||||||
@@ -373,13 +372,23 @@ def add_total_row(out, root_type, balance_must_be, period_list, company_currency
|
|||||||
|
|
||||||
|
|
||||||
def get_accounts(company, root_type):
|
def get_accounts(company, root_type):
|
||||||
return frappe.db.sql(
|
return frappe.get_all(
|
||||||
"""
|
"Account",
|
||||||
select name, account_number, parent_account, lft, rgt, root_type, report_type, account_name, include_in_gross, account_type, is_group, lft, rgt
|
filters={"company": company, "root_type": root_type},
|
||||||
from `tabAccount`
|
fields=[
|
||||||
where company=%s and root_type=%s order by lft""",
|
"name",
|
||||||
(company, root_type),
|
"account_number",
|
||||||
as_dict=True,
|
"parent_account",
|
||||||
|
"lft",
|
||||||
|
"rgt",
|
||||||
|
"root_type",
|
||||||
|
"report_type",
|
||||||
|
"account_name",
|
||||||
|
"include_in_gross",
|
||||||
|
"account_type",
|
||||||
|
"is_group",
|
||||||
|
],
|
||||||
|
order_by="lft",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -529,7 +538,11 @@ def get_accounting_entries(
|
|||||||
gl_entry.credit_in_account_currency
|
gl_entry.credit_in_account_currency
|
||||||
if not group_by_account
|
if not group_by_account
|
||||||
else Sum(gl_entry.credit_in_account_currency).as_("credit_in_account_currency"),
|
else Sum(gl_entry.credit_in_account_currency).as_("credit_in_account_currency"),
|
||||||
gl_entry.account_currency,
|
# when grouping by account the non-aggregated columns must be aggregated for postgres;
|
||||||
|
# account_currency is constant per account so Max() returns the same value.
|
||||||
|
gl_entry.account_currency
|
||||||
|
if not group_by_account
|
||||||
|
else Max(gl_entry.account_currency).as_("account_currency"),
|
||||||
)
|
)
|
||||||
.where(gl_entry.company == filters.company)
|
.where(gl_entry.company == filters.company)
|
||||||
)
|
)
|
||||||
@@ -547,15 +560,29 @@ def get_accounting_entries(
|
|||||||
ignore_is_opening = frappe.get_single_value("Accounts Settings", "ignore_is_opening_check_for_reporting")
|
ignore_is_opening = frappe.get_single_value("Accounts Settings", "ignore_is_opening_check_for_reporting")
|
||||||
|
|
||||||
if doctype == "GL Entry":
|
if doctype == "GL Entry":
|
||||||
query = query.select(gl_entry.posting_date, gl_entry.is_opening, gl_entry.fiscal_year)
|
# aggregate the non-grouped columns when grouping by account (postgres requirement)
|
||||||
|
if group_by_account:
|
||||||
|
query = query.select(
|
||||||
|
Max(gl_entry.posting_date).as_("posting_date"),
|
||||||
|
Max(gl_entry.is_opening).as_("is_opening"),
|
||||||
|
Max(gl_entry.fiscal_year).as_("fiscal_year"),
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
query = query.select(gl_entry.posting_date, gl_entry.is_opening, gl_entry.fiscal_year)
|
||||||
query = query.where(gl_entry.is_cancelled == 0)
|
query = query.where(gl_entry.is_cancelled == 0)
|
||||||
query = query.where(gl_entry.posting_date <= to_date)
|
query = query.where(gl_entry.posting_date <= to_date)
|
||||||
query = query.force_index("posting_date_company_index")
|
# FORCE INDEX is MySQL-only; postgres has no index hints (its planner uses the index anyway)
|
||||||
|
if frappe.db.db_type != "postgres":
|
||||||
|
query = query.force_index("posting_date_company_index")
|
||||||
|
|
||||||
if ignore_opening_entries and not ignore_is_opening:
|
if ignore_opening_entries and not ignore_is_opening:
|
||||||
query = query.where(gl_entry.is_opening == "No")
|
query = query.where(gl_entry.is_opening == "No")
|
||||||
else:
|
else:
|
||||||
query = query.select(gl_entry.closing_date.as_("posting_date"))
|
query = query.select(
|
||||||
|
Max(gl_entry.closing_date).as_("posting_date")
|
||||||
|
if group_by_account
|
||||||
|
else gl_entry.closing_date.as_("posting_date")
|
||||||
|
)
|
||||||
query = query.where(gl_entry.period_closing_voucher == period_closing_voucher)
|
query = query.where(gl_entry.period_closing_voucher == period_closing_voucher)
|
||||||
|
|
||||||
query = apply_additional_conditions(doctype, query, from_date, ignore_closing_entries, filters)
|
query = apply_additional_conditions(doctype, query, from_date, ignore_closing_entries, filters)
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ def execute(filters=None):
|
|||||||
if filters and filters.get("print_in_account_currency") and not filters.get("account"):
|
if filters and filters.get("print_in_account_currency") and not filters.get("account"):
|
||||||
frappe.throw(_("Select an account to print in account currency"))
|
frappe.throw(_("Select an account to print in account currency"))
|
||||||
|
|
||||||
for acc in frappe.db.sql("""select name, is_group from tabAccount""", as_dict=1):
|
for acc in frappe.get_all("Account", fields=["name", "is_group"]):
|
||||||
account_details.setdefault(acc.name, acc)
|
account_details.setdefault(acc.name, acc)
|
||||||
|
|
||||||
if filters.get("party"):
|
if filters.get("party"):
|
||||||
@@ -650,10 +650,8 @@ def get_result_as_list(data, filters):
|
|||||||
|
|
||||||
def get_supplier_invoice_details():
|
def get_supplier_invoice_details():
|
||||||
inv_details = {}
|
inv_details = {}
|
||||||
for d in frappe.db.sql(
|
for d in frappe.get_all(
|
||||||
""" select name, bill_no from `tabPurchase Invoice`
|
"Purchase Invoice", filters={"docstatus": 1, "bill_no": ["is", "set"]}, fields=["name", "bill_no"]
|
||||||
where docstatus = 1 and bill_no is not null and bill_no != '' """,
|
|
||||||
as_dict=1,
|
|
||||||
):
|
):
|
||||||
inv_details[d.name] = d.bill_no
|
inv_details[d.name] = d.bill_no
|
||||||
|
|
||||||
|
|||||||
@@ -713,20 +713,25 @@ class GrossProfitGenerator:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def get_returned_invoice_items(self):
|
def get_returned_invoice_items(self):
|
||||||
returned_invoices = frappe.db.sql(
|
si = frappe.qb.DocType("Sales Invoice")
|
||||||
"""
|
si_item = frappe.qb.DocType("Sales Invoice Item")
|
||||||
select
|
returned_invoices = (
|
||||||
si.name, si_item.item_code, si_item.stock_qty as qty, si_item.base_net_amount as base_amount, si.return_against
|
frappe.qb.from_(si)
|
||||||
from
|
.inner_join(si_item)
|
||||||
`tabSales Invoice` si, `tabSales Invoice Item` si_item
|
.on(si.name == si_item.parent)
|
||||||
where
|
.select(
|
||||||
si.name = si_item.parent
|
si.name,
|
||||||
and si.docstatus = 1
|
si_item.item_code,
|
||||||
and si.is_return = 1
|
si_item.stock_qty.as_("qty"),
|
||||||
and si.posting_date between %(from_date)s and %(to_date)s
|
si_item.base_net_amount.as_("base_amount"),
|
||||||
""",
|
si.return_against,
|
||||||
{"from_date": self.filters.from_date, "to_date": self.filters.to_date},
|
)
|
||||||
as_dict=1,
|
.where(
|
||||||
|
(si.docstatus == 1)
|
||||||
|
& (si.is_return == 1)
|
||||||
|
& si.posting_date.between(self.filters.from_date, self.filters.to_date)
|
||||||
|
)
|
||||||
|
.run(as_dict=1)
|
||||||
)
|
)
|
||||||
|
|
||||||
self.returned_invoices = frappe._dict()
|
self.returned_invoices = frappe._dict()
|
||||||
@@ -1241,7 +1246,4 @@ class GrossProfitGenerator:
|
|||||||
).setdefault(d.parent_item, []).append(d)
|
).setdefault(d.parent_item, []).append(d)
|
||||||
|
|
||||||
def load_non_stock_items(self):
|
def load_non_stock_items(self):
|
||||||
self.non_stock_items = frappe.db.sql_list(
|
self.non_stock_items = frappe.get_all("Item", filters={"is_stock_item": 0}, pluck="name")
|
||||||
"""select name from tabItem
|
|
||||||
where is_stock_item=0"""
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -62,15 +62,10 @@ def get_columns(filters):
|
|||||||
|
|
||||||
|
|
||||||
def get_all_transfers(date, shareholder):
|
def get_all_transfers(date, shareholder):
|
||||||
condition = " "
|
return frappe.get_all(
|
||||||
# if company:
|
"Share Transfer",
|
||||||
# condition = 'AND company = %(company)s '
|
filters={"date": ["<=", date], "docstatus": 1},
|
||||||
return frappe.db.sql(
|
or_filters=[["from_shareholder", "=", shareholder], ["to_shareholder", "=", shareholder]],
|
||||||
f"""SELECT * FROM `tabShare Transfer`
|
fields=["*"],
|
||||||
WHERE ((DATE(date) <= %(date)s AND from_shareholder = %(shareholder)s {condition})
|
order_by="date",
|
||||||
OR (DATE(date) <= %(date)s AND to_shareholder = %(shareholder)s {condition}))
|
|
||||||
AND docstatus = 1
|
|
||||||
ORDER BY date""",
|
|
||||||
{"date": date, "shareholder": shareholder},
|
|
||||||
as_dict=1,
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.query_builder.functions import Sum
|
from frappe.query_builder.functions import Max, Sum
|
||||||
from frappe.utils import add_days, cstr, flt, formatdate, getdate
|
from frappe.utils import add_days, cstr, flt, formatdate, getdate
|
||||||
|
|
||||||
import erpnext
|
import erpnext
|
||||||
@@ -82,12 +82,21 @@ def validate_filters(filters):
|
|||||||
|
|
||||||
|
|
||||||
def get_data(filters):
|
def get_data(filters):
|
||||||
accounts = frappe.db.sql(
|
accounts = frappe.get_all(
|
||||||
"""select name, account_number, parent_account, account_name, root_type, report_type, is_group, lft, rgt
|
"Account",
|
||||||
|
filters={"company": filters.company},
|
||||||
from `tabAccount` where company=%s order by lft""",
|
fields=[
|
||||||
filters.company,
|
"name",
|
||||||
as_dict=True,
|
"account_number",
|
||||||
|
"parent_account",
|
||||||
|
"account_name",
|
||||||
|
"root_type",
|
||||||
|
"report_type",
|
||||||
|
"is_group",
|
||||||
|
"lft",
|
||||||
|
"rgt",
|
||||||
|
],
|
||||||
|
order_by="lft",
|
||||||
)
|
)
|
||||||
company_currency = filters.presentation_currency or erpnext.get_company_currency(filters.company)
|
company_currency = filters.presentation_currency or erpnext.get_company_currency(filters.company)
|
||||||
|
|
||||||
@@ -240,7 +249,8 @@ def get_opening_balance(
|
|||||||
frappe.qb.from_(closing_balance)
|
frappe.qb.from_(closing_balance)
|
||||||
.select(
|
.select(
|
||||||
closing_balance.account,
|
closing_balance.account,
|
||||||
closing_balance.account_currency,
|
# account_currency is constant per grouped account -> Max() keeps the GROUP BY postgres-valid
|
||||||
|
Max(closing_balance.account_currency).as_("account_currency"),
|
||||||
Sum(closing_balance.debit).as_("debit"),
|
Sum(closing_balance.debit).as_("debit"),
|
||||||
Sum(closing_balance.credit).as_("credit"),
|
Sum(closing_balance.credit).as_("credit"),
|
||||||
Sum(closing_balance.debit_in_account_currency).as_("debit_in_account_currency"),
|
Sum(closing_balance.debit_in_account_currency).as_("debit_in_account_currency"),
|
||||||
|
|||||||
Reference in New Issue
Block a user